DEV Community

Tom Wang
Tom Wang

Posted on Originally published at tomcn.uk

rust_decimal vs bigdecimal: Money Types in Rust

Decimal::from_str("100000000000.000000000000000001") returns Ok. The value inside is 100000000000.00000000000000000: rust_decimal dropped the last wei to fit its 96-bit mantissa and raised no error. Call Decimal::from_str_exact on the same string and you get Err(Underflow).

The pages ranking for "rust_decimal vs bigdecimal" mostly stop at "fixed-size and fast versus arbitrary precision", which is true and not enough to choose with. So I built a scratch crate against rust_decimal 1.43.0 and bigdecimal 0.4.11 on Rust 1.98 and ran the cases payment code hits: token amounts, rounding, JSON, Postgres and overflow. Unless I say otherwise, every output below is pasted from that run.

How Should You Represent Money in Rust?

There are five realistic options, and one of them is wrong.

Type Exact decimals? Size Heap? Range Use it for
f64 No 8 bytes No 15 to 17 significant digits Nothing involving amounts
i64 minor units Yes 8 bytes No ±9.22 × 10¹⁸ minor units Fiat balances and postings
i128 / u128 minor units Yes 16 bytes No up to 3.4 × 10³⁸ Token balances, TigerBeetle-style ledgers
rust_decimal::Decimal Yes, to 28 digits 16 bytes No ±79,228,162,514,264,337,593,543,950,335 Rates, fees, tax, FX, API amounts
bigdecimal::BigDecimal Yes, unbounded 40 bytes + digits Yes Memory Boundaries where inputs can exceed 28 digits

f64 fails the first test anyone runs. Adding 0.1 ten times gives 0.9999999999999999, and 0.1 + 0.2 == 0.3 is false. Both decimal crates return true.

Integer minor units are what Stripe and Adyen put on the wire, and what I used for the Postgres schema in the TigerBeetle vs Postgres ledger guide. An i64 holds 92,233,720,368,547,758.07 when the unit is pence. No fiat ledger gets close. The same i64 holds 9.223372036854775807 ETH when the unit is wei. That gap between fiat and 18-decimal tokens shapes most of what follows.

rust_decimal vs bigdecimal vs fastnum in 2026: Which Crate?

rust_decimal 1.43.0 bigdecimal 0.4.11 fastnum 0.7.5
Representation 96-bit integer, scale 0 to 28, sign bit BigInt plus i64 scale Fixed N-bit coefficient plus 64-bit control block
Significant digits 28 (29 in some cases) Unbounded 19 (D64), 38 (D128), 77 (D256), 154 (D512)
Copy, no heap Yes No (Clone, heap digits) Yes
Default rounding Half-even Half-even for round, truncation for with_scale Half-up
NaN and Infinity No No Yes
serde default String out; string or number in String out; string or number in String out; string only in
Postgres support sqlx, Diesel, tokio-postgres sqlx, Diesel sqlx, Diesel, tokio-postgres
Total downloads (3 Nov 2026) 169.1M 139.5M 10.6M
Latest release 2 Sep 2026 28 Sep 2026 11 Jun 2026, pre-1.0

Read the full article on tomcn.uk →


About the Author

I'm Tom Wang, an AI Developer & Fintech Developer — building AI agents, crypto payment infrastructure, and cross-border payout systems with Rust, Go, and TypeScript. Based in London, UK.

Currently open to new opportunities in fintech, crypto payments, and AI agent engineering.

Top comments (0)