money-safe
v0.1.0TYPE-SAFE MONEY
DOCS INTERFACE · GUIDE / RECIPES / REFERENCE · MINOR UNITS STAY EXPLICIT
System Boundaries

System Boundaries

Money usually crosses several boundaries. The safest shape depends on where the value is crossing.

money-safe focuses on amount shape: parsing, integer minor units, arithmetic, allocation, formatting, and serialized payloads. It does not own exchange rates, accounting ledgers, tax policy, provider orchestration, or product pricing rules.

Browser and public API input

Use decimal strings:

json
{
  "amount": "19.99",
  "currency": "CNY"
}
ts
const value = amount(payload.amount, payload.currency);

Database and payment providers

Use minor units:

sql
amount_minor BIGINT NOT NULL,
currency CHAR(3) NOT NULL,
minor_unit SMALLINT NOT NULL
ts
const value = amount.minor(row.amount_minor, row.currency, {
  minorUnit: row.minor_unit
});

Service-to-service payloads

Use serialized money:

json
{
  "amountMinor": "1999",
  "currency": "CNY",
  "minorUnit": 2
}
ts
const value = amount.fromJSON(payload);

amountMinor is a string so large values can move across JSON without passing through JavaScript Number.

Display

Format only at display boundaries:

ts
amount('19.99', 'CNY').format('zh-CN');

Do not feed formatted strings back into business logic.

Business policy stays in your app

Keep policy decisions next to the business flow that owns them:

  • Which tax rate applies.
  • Which payment provider receives the payload.
  • Which ledger account records the movement.
  • Which exchange rate source is trusted.

Use money-safe for the money value that crosses those boundaries, not as the owner of those policies.