
Dinero Formatting
- 7 installs
- 6.8k repo stars
- Updated August 1, 2026
- dinerojs/dinero.js
Format Dinero.js monetary values for display with currency symbols, locale awareness, and serialization.
About
Formatting patterns for displaying Dinero.js monetary values with currency symbols and locale-aware output. A developer uses it when rendering prices and totals or serializing money objects.
- Use toDecimal for display and compose with Intl.NumberFormat for currency symbols
- Locale-aware and non-decimal currency formatting plus serialization patterns
Dinero Formatting by the numbers
- 7 all-time installs (skills.sh)
- Ranked #826 of 1,106 Finance & Trading skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/dinerojs/dinero.js --skill dinero-formattingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 7 |
|---|---|
| repo stars | ★ 6.8k |
| Last updated | August 1, 2026 |
| Repository | dinerojs/dinero.js ↗ |
What it does
Format Dinero.js monetary values for display with currency symbols, locale awareness, and serialization.
Files
Dinero.js Formatting
Patterns for formatting Dinero.js monetary values for display. Covers currency symbols, locale-aware formatting, non-decimal currencies, and serialization.
When to Apply
Reference these guidelines when:
- Displaying prices, totals, or monetary values in a UI
- Adding currency symbols or locale-specific formatting
- Formatting non-decimal currencies (e.g., historical currencies with non-base-10 subdivisions)
- Serializing Dinero objects for APIs, databases, or transport
- Building reusable formatting utilities
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Display | CRITICAL | display- |
| 2 | Locale | HIGH | locale- |
| 3 | Serialization | HIGH | serialization- |
| 4 | Non-Decimal | MEDIUM | nondecimal- |
Quick Reference
1. Display (CRITICAL)
display-to-decimal- UsetoDecimalfor display strings, nottoSnapshotdisplay-no-currency-symbols- Dinero.js does not format currency symbols; compose withIntl.NumberFormat
2. Locale (HIGH)
locale-intl-formatter- Build reusable formatters withIntl.NumberFormatlocale-multilingual- Create locale-parameterized formatters for multilingual sites
3. Serialization (HIGH)
serialization-snapshot- UsetoSnapshotfor transport and storage, not displayserialization-bigint-json- BigInt Dinero objects require a custom JSON replacer
4. Non-Decimal (MEDIUM)
nondecimal-to-units- UsetoUnitsfor non-decimal currencies, nottoDecimal
How to Use
Read individual rule files for detailed explanations and code examples:
rules/display-no-currency-symbols.md
rules/locale-intl-formatter.mdEach rule file contains:
- Brief explanation of why it matters
- Incorrect code example with explanation
- Correct code example with explanation
- Additional context and references
Dinero.js Does Not Format Currency Symbols — Compose with Intl.NumberFormat
toDecimal returns a plain decimal string like "19.99", not "$19.99". This is by design: currency formatting varies by locale ($19.99 in en-US, 19,99 $US in fr-CA, 19,99 $ in fr-FR). Use toDecimal with a transformer to add locale-aware formatting.
Incorrect (expecting currency symbols from toDecimal):
import { dinero, toDecimal } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const price = dinero({ amount: 1999, currency: USD });
toDecimal(price); // "19.99" — no currency symbolCorrect (composing with Intl.NumberFormat):
import { dinero, toDecimal } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const price = dinero({ amount: 1999, currency: USD });
toDecimal(price, ({ value, currency }) => {
return Number(value).toLocaleString('en-US', {
style: 'currency',
currency: currency.code,
});
}); // "$19.99"Reference: https://v2.dinerojs.com/faq/why-no-currency-formatting
Use toDecimal for Display Strings, Not toSnapshot
toDecimal returns a human-readable decimal string (e.g., "19.99"). toSnapshot returns the raw internal representation in minor units (e.g., { amount: 1999, ... }). Use the right one for the right job.
Incorrect (using toSnapshot for display):
import { dinero, toSnapshot } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const price = dinero({ amount: 1999, currency: USD });
const { amount } = toSnapshot(price);
display.textContent = `$${amount}`; // Shows "$1999" — wrongCorrect (using toDecimal for display):
import { dinero, toDecimal } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const price = dinero({ amount: 1999, currency: USD });
toDecimal(price); // "19.99"toSnapshot is for serialization (APIs, databases, transport). toDecimal is for rendering to users.
Reference: https://v2.dinerojs.com/core-concepts/formatting
Build Reusable Formatters with Intl.NumberFormat
Instead of inlining Intl.NumberFormat at every call site, build a reusable formatter function.
Correct (reusable formatter):
import { toDecimal } from 'dinero.js';
function intlFormat(dineroObject, locale, options = {}) {
function transformer({ value, currency }) {
return Number(value).toLocaleString(locale, {
...options,
style: 'currency',
currency: currency.code,
});
}
return toDecimal(dineroObject, transformer);
}
intlFormat(price, 'en-US'); // "$19.99"
intlFormat(price, 'fr-FR'); // "19,99 $US"
intlFormat(price, 'ja-JP'); // "$19.99"You can also create a higher-order function that bakes in the locale:
function createFormatter(locale, options = {}) {
return function format(dineroObject) {
return intlFormat(dineroObject, locale, options);
};
}
const formatUSD = createFormatter('en-US');
formatUSD(price); // "$19.99"Reference: https://v2.dinerojs.com/guides/formatting-in-a-multilingual-site
Parameterize Locale for Multilingual Sites
In multilingual applications, pass the locale as a parameter rather than hardcoding it. This lets you format the same Dinero object differently depending on the user's language.
Incorrect (hardcoded locale):
function formatPrice(dineroObject) {
return toDecimal(dineroObject, ({ value, currency }) => {
return Number(value).toLocaleString('en-US', {
style: 'currency',
currency: currency.code,
});
});
}Correct (locale as parameter):
function formatPrice(dineroObject, locale) {
return toDecimal(dineroObject, ({ value, currency }) => {
return Number(value).toLocaleString(locale, {
style: 'currency',
currency: currency.code,
});
});
}
formatPrice(price, 'en-US'); // "$19.99"
formatPrice(price, 'de-DE'); // "19,99 $"
formatPrice(price, 'ja-JP'); // "$19.99"In React, you can get the locale from your i18n context (e.g., next-intl, react-intl, react-i18next) and pass it to your formatter.
Reference: https://v2.dinerojs.com/guides/formatting-in-a-multilingual-site
Use toUnits for Non-Decimal Currencies, Not toDecimal
toDecimal assumes a decimal (base 10) currency. For currencies with non-decimal subdivisions (e.g., base 6, base 12, or multi-base like pre-decimal GBP), use toUnits.
Incorrect (toDecimal on non-decimal currency):
import { dinero, toDecimal } from 'dinero.js';
const GRD = { code: 'GRD', base: 6, exponent: 1 };
const d = dinero({ amount: 9, currency: GRD });
toDecimal(d); // Throws or produces meaningless outputCorrect (toUnits with a custom transformer):
import { dinero, toUnits } from 'dinero.js';
const GRD = { code: 'GRD', base: 6, exponent: 1 };
const d = dinero({ amount: 9, currency: GRD });
const labels = ['drachma', 'obol'];
toUnits(d, ({ value }) =>
value
.filter((v) => v > 0)
.map((v, i) => `${v} ${labels[i]}`)
.join(', '),
); // "1 drachma, 3 obols"toUnits returns an array of unit values, one per subdivision level. It works with any base, including array bases like [20, 12] for pre-decimal GBP (pounds, shillings, pence).
Reference: https://v2.dinerojs.com/guides/formatting-non-decimal-currencies
BigInt Dinero Objects Require a Custom JSON Replacer
JSON.stringify throws a TypeError on bigint values. When using the bigint calculator, provide a custom replacer.
Incorrect (stringify without replacer):
import { dinero, toSnapshot } from 'dinero.js/bigint';
import { USD } from 'dinero.js/bigint/currencies';
const price = dinero({ amount: 500n, currency: USD });
JSON.stringify(toSnapshot(price)); // TypeError: Do not know how to serialize a BigIntCorrect (with replacer):
import { dinero, toSnapshot } from 'dinero.js/bigint';
import { USD } from 'dinero.js/bigint/currencies';
const price = dinero({ amount: 500n, currency: USD });
JSON.stringify(toSnapshot(price), (key, value) => {
if (typeof value === 'bigint') {
return String(value);
}
return value;
});When restoring, convert string values back to bigint:
const data = JSON.parse(json, (key, value) => {
if (typeof value === 'string' && /^\d+$/.test(value)) {
return BigInt(value);
}
return value;
});
const restored = dinero(data.price);Reference: https://v2.dinerojs.com/guides/transporting-and-restoring
Use toSnapshot for Transport and Storage, Not Display
toSnapshot returns the full internal representation as a plain object, suitable for JSON serialization. Use it for APIs, databases, and transport. Use toDecimal for user-facing display.
Correct (serialization with toSnapshot):
import { dinero, toSnapshot } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const price = dinero({ amount: 1999, currency: USD });
const snapshot = toSnapshot(price);
// { amount: 1999, currency: { code: 'USD', base: 10, exponent: 2 }, scale: 2 }
// Send to API
await fetch('/api/products', {
method: 'POST',
body: JSON.stringify({ price: snapshot }),
});Correct (restoring from snapshot):
import { dinero } from 'dinero.js';
// The snapshot can be passed directly to dinero()
const restored = dinero(data.price);Snapshots are plain objects with no methods, making them safe for JSON.stringify, database columns, and cross-service communication.
Reference: https://v2.dinerojs.com/guides/transporting-and-restoring