
Dinero Best Practices
- 11 installs
- 6.8k repo stars
- Updated August 1, 2026
- dinerojs/dinero.js
Apply Dinero.js best practices for creating money objects, arithmetic, and precision in JavaScript/TypeScript.
About
Core best practices for the Dinero.js money library covering object creation, arithmetic, precision, and imports. A developer uses it when handling monetary values safely in JavaScript/TypeScript.
- Object-creation rules: integer minor units, float-conversion helpers, zero-exponent currencies
- Arithmetic rules: immutability, allocate for splitting, scaled amounts over raw decimals
Dinero Best Practices by the numbers
- 11 all-time installs (skills.sh)
- Ranked #798 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-best-practicesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 11 |
|---|---|
| repo stars | ★ 6.8k |
| Last updated | August 1, 2026 |
| Repository | dinerojs/dinero.js ↗ |
What it does
Apply Dinero.js best practices for creating money objects, arithmetic, and precision in JavaScript/TypeScript.
Files
Dinero.js Best Practices
Core rules for working with Dinero.js, the JavaScript/TypeScript library for creating, calculating, and formatting money safely. Contains rules across 4 categories, prioritized by impact.
When to Apply
Reference these guidelines when:
- Creating Dinero objects from user input, API responses, or database values
- Performing arithmetic on monetary values (adding, splitting, multiplying)
- Choosing between
numberandbigintcalculators - Importing from
dinero.js,dinero.js/currencies, ordinero.js/bigint - Working with prices, costs, taxes, or any financial calculation
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Object Creation | CRITICAL | creation- |
| 2 | Arithmetic | CRITICAL | arithmetic- |
| 3 | Precision | HIGH | precision- |
| 4 | Imports | MEDIUM | imports- |
Quick Reference
1. Object Creation (CRITICAL)
creation-minor-units- Always pass amounts as integers in minor currency unitscreation-from-floats- Use a helper to convert float inputs to minor unitscreation-zero-exponent- Currencies with exponent 0 (e.g., JPY) take major units directly
2. Arithmetic (CRITICAL)
arithmetic-immutability- All operations return new objects; capture the return valuearithmetic-allocate-not-divide- Useallocatefor splitting money, not manual divisionarithmetic-scaled-amounts- Never multiply by a raw decimal; use scaled amountsarithmetic-percentages- Calculate percentages withallocateor scaledmultiply
3. Precision (HIGH)
precision-bigint- Usedinero.js/bigintfor amounts exceedingNumber.MAX_SAFE_INTEGERprecision-crypto- Cryptocurrencies require bigint due to high exponentsprecision-trim-scale- UsetrimScaleto remove trailing zeros after chained operations
4. Imports (MEDIUM)
imports-tree-shaking- Import only what you use; standalone functions enable tree-shakingimports-bigint-currencies- Match calculator type: usedinero.js/bigint/currencieswithdinero.js/bigint
How to Use
Read individual rule files for detailed explanations and code examples:
rules/creation-minor-units.md
rules/arithmetic-allocate-not-divide.mdEach rule file contains:
- Brief explanation of why it matters
- Incorrect code example with explanation
- Correct code example with explanation
- Additional context and references
Use allocate for Splitting Money, Not Manual Division
When splitting money between parties, use allocate instead of dividing manually. allocate distributes remainders so no money is lost.
Incorrect (manual division loses money):
import { dinero, multiply } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const total = dinero({ amount: 1003, currency: USD }); // $10.03
// Splitting three ways: 1003 / 3 = 334.33... — where does the extra cent go?
const share = multiply(total, { amount: 1, scale: 0 }); // No good way to split evenlyCorrect (allocate distributes remainders):
import { dinero, allocate } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const total = dinero({ amount: 1003, currency: USD }); // $10.03
const shares = allocate(total, [1, 1, 1]);
// [$3.35, $3.34, $3.34] — extra cent goes to the first shareThe ratios in allocate are relative. [1, 1, 1] splits evenly. [70, 20, 10] splits 70%/20%/10%.
Reference: https://v2.dinerojs.com/api/mutations/allocate
Capture Return Values — Dinero Objects Are Immutable
All Dinero.js operations are pure functions that return new objects. The original objects are never modified. Discarding the return value means losing your calculation.
Incorrect (discarding the return value):
import { dinero, add } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const price = dinero({ amount: 1000, currency: USD });
const tax = dinero({ amount: 100, currency: USD });
add(price, tax); // Return value discarded — price is unchangedCorrect (capturing the result):
import { dinero, add } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const price = dinero({ amount: 1000, currency: USD });
const tax = dinero({ amount: 100, currency: USD });
const total = add(price, tax); // $11.00This applies to all operations: add, subtract, multiply, allocate, convert, trimScale, transformScale, and normalizeScale.
Reference: https://v2.dinerojs.com/core-concepts/mutations
Calculate Percentages with allocate or Scaled multiply
There are two safe ways to calculate percentages of a monetary value: allocate (for splitting into complementary parts) and multiply with a scaled amount (for extracting a percentage).
Incorrect (float percentage):
import { dinero, multiply } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const subtotal = dinero({ amount: 5000, currency: USD });
const tax = multiply(subtotal, 0.15); // Risky: may throw if result is non-integerCorrect (allocate for complementary parts):
import { dinero, allocate } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const subtotal = dinero({ amount: 5000, currency: USD });
const [tax, net] = allocate(subtotal, [15, 85]); // 15% tax, 85% netCorrect (scaled multiply for a single percentage):
import { dinero, multiply } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const subtotal = dinero({ amount: 5000, currency: USD });
const tax = multiply(subtotal, { amount: 15, scale: 2 }); // 15/100 = 15%Use allocate when you need both parts (e.g., tax and net) to guarantee they sum to the original. Use multiply when you only need one part.
Reference: https://v2.dinerojs.com/guides/calculating-percentages
Never Multiply by a Raw Decimal — Use Scaled Amounts
Dinero.js uses integer arithmetic. Multiplying by a decimal that produces a non-integer result will throw. Use scaled amounts instead: { amount, scale } represents amount / (base ^ scale).
Incorrect (raw decimal multiplier):
import { dinero, multiply } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const price = dinero({ amount: 1001, currency: USD });
multiply(price, 0.5); // Throws: 1001 * 0.5 = 500.5 (not an integer)Correct (scaled amount):
import { dinero, multiply } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const price = dinero({ amount: 1001, currency: USD });
multiply(price, { amount: 5, scale: 1 }); // 5/10 = 0.5, result: amount 5005, scale 3Common scaled amounts:
| Decimal | Scaled amount |
|---|---|
| 0.5 | { amount: 5, scale: 1 } |
| 0.1 | { amount: 1, scale: 1 } |
| 0.15 | { amount: 15, scale: 2 } |
| 1.5 | { amount: 15, scale: 1 } |
Reference: https://v2.dinerojs.com/faq/can-i-multiply-by-a-decimal
Convert Float Inputs to Minor Units with a Helper
When receiving float values from external sources (APIs, user input, databases), convert them to integer minor units before creating a Dinero object. Never pass floats directly.
Incorrect (passing a float directly):
import { dinero } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const priceFromApi = 19.99;
const d = dinero({ amount: priceFromApi, currency: USD }); // ThrowsCorrect (converting with a helper):
import { dinero } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
function dineroFromFloat({ amount: float, currency, scale }) {
const factor = currency.base ** (scale ?? currency.exponent);
const amount = Math.round(float * factor);
return dinero({ amount, currency, scale });
}
const priceFromApi = 19.99;
const d = dineroFromFloat({ amount: priceFromApi, currency: USD }); // $19.99Math.round is necessary to avoid floating-point artifacts (e.g., 19.99 * 100 evaluates to 1998.9999999999998 in JavaScript).
Reference: https://v2.dinerojs.com/guides/creating-from-floats
Always Pass Amounts as Integers in Minor Currency Units
Dinero.js represents money in the smallest subdivision of a currency. For USD (exponent 2), the amount is in cents. Passing a major-unit value silently creates the wrong amount.
Incorrect (passing major units or floats):
import { dinero } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
// Wrong: 50 cents, not 50 dollars
const d = dinero({ amount: 50, currency: USD });
// Wrong: throws on non-integer
const d = dinero({ amount: 19.99, currency: USD });Correct (minor units as integers):
import { dinero } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const d1 = dinero({ amount: 5000, currency: USD }); // $50.00
const d2 = dinero({ amount: 1999, currency: USD }); // $19.99Reference: https://v2.dinerojs.com/core-concepts/amount
Currencies with Exponent 0 Take Major Units Directly
Currencies like JPY and KRW have no minor units (exponent 0). The amount you pass is in major units directly.
Incorrect (treating JPY like USD):
import { dinero } from 'dinero.js';
import { JPY } from 'dinero.js/currencies';
// Wrong: this is 500,000 yen, not 5,000 yen
const d = dinero({ amount: 500000, currency: JPY });Correct (major units for zero-exponent currencies):
import { dinero } from 'dinero.js';
import { JPY } from 'dinero.js/currencies';
// JPY has exponent 0, so 5000 means 5,000 yen
const d = dinero({ amount: 5000, currency: JPY });Check a currency's exponent property to determine the expected unit. USD has exponent 2 (cents), BHD has exponent 3 (fils), JPY has exponent 0 (yen).
Reference: https://v2.dinerojs.com/core-concepts/amount
Match Calculator Type — Use Matching Currency Imports
Currency definitions from dinero.js/currencies use number for base and exponent. Currency definitions from dinero.js/bigint/currencies use bigint. Mixing them throws a TypeError.
Incorrect (mixing number currencies with bigint calculator):
import { dinero } from 'dinero.js/bigint';
import { USD } from 'dinero.js/currencies'; // number-typed
// TypeError: Cannot mix BigInt and other types
const d = dinero({ amount: 500n, currency: USD });Correct (matching imports):
// Number calculator + number currencies
import { dinero } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const d = dinero({ amount: 500, currency: USD });
// Bigint calculator + bigint currencies
import { dinero } from 'dinero.js/bigint';
import { USD } from 'dinero.js/bigint/currencies';
const d = dinero({ amount: 500n, currency: USD });Reference: https://v2.dinerojs.com/faq/why-cant-i-use-currencies-with-bigint
Import Only What You Use — Standalone Functions Enable Tree-Shaking
Dinero.js exports standalone functions instead of methods on objects. This means bundlers can eliminate unused code. Import only the functions you need.
How it works:
// Only add, toDecimal, and dinero are included in your bundle
import { dinero, add, toDecimal } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const total = add(
dinero({ amount: 1000, currency: USD }),
dinero({ amount: 500, currency: USD }),
);
toDecimal(total); // "15.00"Functions like multiply, allocate, compare, greaterThan, etc. are not shipped if you don't import them.
Note: Dinero.js uses standalone functions, not methods. Write add(d1, d2), not d1.add(d2).
Reference: https://v2.dinerojs.com/faq/why-functions-instead-of-methods
Use bigint for Amounts Exceeding Number.MAX_SAFE_INTEGER
JavaScript number silently loses precision beyond Number.MAX_SAFE_INTEGER (9,007,199,254,740,991). For large monetary values, use the bigint entry point.
Incorrect (large amount with number calculator):
import { dinero } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
// 25800000000000000 exceeds safe integer range — silently wrong
const d = dinero({ amount: 25800000000000000, currency: USD });Correct (bigint calculator):
import { dinero } from 'dinero.js/bigint';
import { USD } from 'dinero.js/bigint/currencies';
const d = dinero({ amount: 25800000000000000n, currency: USD });Note: dinero.js/bigint uses its own currency definitions where base and exponent are bigint values. Always import currencies from dinero.js/bigint/currencies when using the bigint calculator.
Reference: https://v2.dinerojs.com/guides/precision-and-large-numbers
Cryptocurrencies Require bigint Due to High Exponents
Cryptocurrencies like ETH (exponent 18) and BTC (exponent 8) produce amounts that exceed the safe integer range even for small values. Always use the bigint calculator for crypto.
Incorrect (number calculator for ETH):
import { dinero } from 'dinero.js';
const ETH = { code: 'ETH', base: 10, exponent: 18 };
// 1 ETH = 1000000000000000000 wei — exceeds Number.MAX_SAFE_INTEGER
const d = dinero({ amount: 1000000000000000000, currency: ETH });Correct (bigint calculator):
import { dinero } from 'dinero.js/bigint';
const ETH = { code: 'ETH', base: 10n, exponent: 18n };
const d = dinero({ amount: 1000000000000000000n, currency: ETH });Avoid naming files after cryptocurrency ticker codes (e.g., xbt.js, xmr.js). Ad blockers may flag these file names as crypto mining scripts and block them from loading.
Reference: https://v2.dinerojs.com/guides/cryptocurrencies
Use trimScale to Remove Trailing Zeros After Chained Operations
Dinero.js automatically promotes to the highest scale when combining objects with different scales. Over many operations, scale can grow unnecessarily. Use trimScale to drop trailing zeros.
Before trimming:
import { dinero, add, trimScale } from 'dinero.js';
import { USD } from 'dinero.js/currencies';
const d1 = dinero({ amount: 100, currency: USD });
const d2 = dinero({ amount: 2000000, currency: USD, scale: 6 });
const result = add(d1, d2); // amount: 3000000, scale: 6After trimming:
const trimmed = trimScale(result); // amount: 300, scale: 2This is especially useful before serialization (storing or transporting) where compact representation matters.
Reference: https://v2.dinerojs.com/api/conversions/trim-scale