Tiny human-readable number formatter built on native Intl.
Turn numbers into "1.2M", "€1,999.00", "3.2 GB", or "120 km/h".
One function. Smart defaults. Any locale. ~0.7kb gzip. Zero dependencies.
Intl.NumberFormat is powerful. anyamount makes it usable.
Built for dashboards, feeds, pricing pages, file lists, and stats — anywhere a raw number should read like a person wrote it. No locale files. No plugins. No config.
import { anyamount } from "anyamount";
anyamount(1234567);
// "1.2M" — smart mode (default)
anyamount(42);
// "42"
anyamount(1999, { mode: "currency", currency: "EUR" });
// "€1,999.00"
anyamount(3.2, { mode: "unit", unit: "gigabyte" });
// "3.2 GB"
anyamount(120, { mode: "unit", unit: "kilometer-per-hour", locale: "ru" });
// "120 км/ч"npm install anyamountanyamount(value);
anyamount(value, options);value is a number.
anyamount(1234567);
anyamount(0.1234);
anyamount(-42.5);The mode option picks the rendering strategy. Default is "smart".
Context-aware. Compact notation for big numbers, plain formatting for small
ones — the cutoff is |value| >= 10000.
anyamount(1234567, { locale: "en" }); // "1.2M"
anyamount(10000, { locale: "en" }); // "10K"
anyamount(9999, { locale: "en" }); // "9,999"
anyamount(42, { locale: "en" }); // "42"
anyamount(0.1234, { locale: "en" }); // "0.12"
anyamount(1234567, { locale: "en", style: "long" });
// "1.2 million"
anyamount(1234567, { locale: "en", digits: 2 });
// "1.23M"Fraction digits default to 2 for plain numbers and 1 for compact ones.
Reads: locale, style, digits.
Money via the Intl.NumberFormat currency style. currency is required —
any ISO 4217 code.
anyamount(1999, { mode: "currency", currency: "EUR", locale: "en" });
// "€1,999.00"
anyamount(1999, { mode: "currency", currency: "RSD", locale: "sr" });
// "1.999,00 RSD"
anyamount(1999, { mode: "currency", currency: "JPY", locale: "ja" });
// "¥1,999" — JPY has no minor unit, Intl knows
anyamount(1999.99, { mode: "currency", currency: "EUR", locale: "en", digits: 0 });
// "€2,000"Fraction digits default to the currency's own (2 for EUR, 0 for JPY).
Reads: locale, currency, digits.
Measurements via the Intl.NumberFormat unit style. unit is required —
any sanctioned identifier, including compound "<unit>-per-<unit>" pairs.
The unit option is typed as a union, so your editor autocompletes it.
anyamount(3.2, { mode: "unit", unit: "gigabyte", locale: "en" });
// "3.2 GB"
anyamount(120, { mode: "unit", unit: "kilometer-per-hour", locale: "en" });
// "120 km/h"
anyamount(3.2, { mode: "unit", unit: "gigabyte", locale: "en", style: "long" });
// "3.2 gigabytes"
anyamount(5, { mode: "unit", unit: "kilometer", locale: "en", style: "narrow" });
// "5km"Fraction digits default to 2.
Reads: locale, unit, style, digits.
| Option | Type | Default | Used by |
|---|---|---|---|
mode |
"smart" | "currency" | "unit" |
"smart" |
— |
locale |
string | string[] |
runtime locale | all |
currency |
string (ISO 4217) |
— (required) | currency |
unit |
sanctioned unit identifier | — (required) | unit |
style |
"long" | "short" | "narrow" |
"short" |
smart, unit |
digits |
number (max fraction digits) |
smart default | all |
Each mode reads only the options that apply to it. The rest are ignored.
currency mode without currency, or unit mode without unit, throws a
clear TypeError.
anyamountParts() accepts the same arguments as anyamount() and returns the
Intl.NumberFormat.formatToParts output unchanged — style the number apart
from the currency symbol or unit, or rebuild the string your own way.
import { anyamountParts } from "anyamount";
anyamountParts(1999, { mode: "currency", currency: "EUR", locale: "en" });
// [
// { type: "currency", value: "€" },
// { type: "integer", value: "1" },
// { type: "group", value: "," },
// { type: "integer", value: "999" },
// { type: "decimal", value: "." },
// { type: "fraction", value: "00" },
// ]
// React: shrink the currency symbol
anyamountParts(price, { mode: "currency", currency: "EUR" }).map((p, i) =>
p.type === "currency" ? <small key={i}>{p.value}</small> : p.value,
);Pass any valid BCP 47 tag — including regional variants like en-GB, zh-TW,
pt-BR. Fallback arrays also work.
anyamount(1234567, { locale: "ru" }); // "1,2 млн"
anyamount(1234567, { locale: "de" }); // "1,2 Mio."
anyamount(1234567, { locale: "ja" }); // "123.5万"
anyamount(1234567, { locale: ["sr-Latn-RS", "en"] });
anyamount(1999, { mode: "currency", currency: "USD", locale: "de" });
// "1.999,00 $"When omitted, native Intl uses the runtime locale.
Output is pure — no Date.now(), no environment reads — so server and client
render identically. SSR-safe by construction.
| anyamount | pretty-bytes | filesize | numeral | |
|---|---|---|---|---|
| gzip | ~0.7kb | ~1kb | ~3kb | ~5kb |
| currency | yes | no | no | yes |
| units beyond bytes | yes | no | no | no |
| localized output | 200+ locales | partial | partial | manual locale files |
| dependencies | 0 | 0 | 0 | 0 |
Honest ones:
- No byte auto-scaling yet.
anyamount(3200000000, { mode: "unit", unit: "byte" })will not pickGBfor you — pass the unit you want. Auto-scaling is planned for v0.2. - No percent mode, no ranges, no parsing. v0.1 is deliberately one function, three modes.
- Exact output strings come from
Intland may vary between ICU versions — don't snapshot them across environments. - Sanctioned units only.
Intlsupports a fixed list of unit identifiers (and-per-compounds of them) — no arbitrary custom units.
anyamount follows semver. This is a 0.x trial
release: the API is small and may still move before 1.0. New options arrive
in minors; exact formatted strings come from Intl and may vary between ICU
versions, so never assert on them across environments.
Node.js 18+ · Chrome 77+ · Firefox 78+ · Safari 14.1+ · Edge Runtime · Cloudflare Workers · Deno
CI runs the full suite on Node 20, 22, and 24.
- anywhen — tiny smart date formatter. One function, three modes, any locale.
- anyamount — you are here.
