Number.prototype.toFixed()

The standard way to format a number for display, and a reliable source of confusion: it returns a string, and its rounding follows the binary value rather than the decimal one you wrote.

Number methodES3 (1999)Live demo
Common call
price.toFixed(2)
Returns
a string with that many decimals
Replaces
manual Math.round(n * 100) / 100 arithmetic
Watch out
a STRING, and 1.005 rounds DOWN
number.toFixed([digits])
→ string

Demo

Live evaluation
Try:
Inputs
nnumbera number
dnumberdecimal places
Output
(3.14159).toFixed(2)
'3.14'

The first case is the everyday use. The second and third are the ones that generate bug reports: 1.005 formatted to two places gives '1.00', not '1.01'. Nothing is broken — the literal 1.005 cannot be represented exactly in binary floating point, and the value actually stored is very slightly BELOW 1.005, so rounding down is correct for the number that exists. The same applies to 1.045. Note also that the output is padded with zeros to reach the requested width, and that every result here is a string.

Parameters

NameTypeRequiredDescription
digitsnumberno (0)Decimal places to show, 0 to 100. Anything outside that range throws RangeError. Trailing zeros are added to reach the count.

Return value

string — A STRING with exactly the requested number of decimal places. Not a number — arithmetic on the result concatenates instead of adding.

Common patterns

Format for display
The result is text, so use it as text.
el.textContent = `$${price.toFixed(2)}`;
Store money as integers
Cents, not dollars — no floating point at all.
const cents = 1005;
const shown = (cents / 100).toFixed(2);
Format with Intl instead
Handles currency, grouping and locale.
new Intl.NumberFormat('en-US', {style: 'currency', currency: 'USD'}).format(price);

Examples

1. Two decimals
(3.14159).toFixed(2)
Returns
'3.14'
2. Rounds DOWN
(1.005).toFixed(2)
Returns
'1.00'
3. Padded
(1.5).toFixed(4)
Returns
'1.5000'
4. It is a string
typeof (1).toFixed(2)
Returns
'string'
5. Huge numbers bail
(1e21).toFixed(2)
Returns
'1e+21'
6. Out of range
(1).toFixed(101)
Returns
RangeError: toFixed() digits argument must be between 0 and 100

Pitfalls

1. It returns a string, not a number
The most common mistake. Adding the result to another value concatenates, and comparisons against numbers do the wrong thing. If you need a number back you have to convert it, which usually means you wanted a different tool entirely.
Concatenation
(1).toFixed(2) + 1
'1.001'
Convert back
Number((1).toFixed(2)) + 1
2
2. 1.005 does not round up
Not a bug in toFixed. The double closest to 1.005 is slightly less than 1.005, so rounding to two places correctly gives 1.00. Any decimal that cannot be written exactly in binary can behave this way, which is why money should not be held in floating point at all.
Surprising
(1.005).toFixed(2)
'1.00'
Integer cents
(Math.round(1.005 * 1000) / 10).toFixed(0)
'101' // work in smaller units
3. Very large numbers fall back to exponential
At 1e21 and above the method abandons fixed notation and returns the exponential form instead, so output you expected to be digit-for-digit predictable suddenly is not.
Not fixed at all
(1e21).toFixed(2)
'1e+21'
Use Intl
new Intl.NumberFormat().format(1e21)
grouped digits
4. It is not locale-aware
The decimal separator is always a dot and there is no digit grouping, so output shown to users in most of Europe is wrong. toLocaleString or Intl.NumberFormat handle both.
Always a dot
(1234.5).toFixed(2)
'1234.50'
Locale-aware
(1234.5).toLocaleString('de-DE', {minimumFractionDigits: 2})
'1.234,50'

When to use

Use it
  • Formatting a number for display with a fixed number of decimals
  • Producing a consistent string for a log or a fixed-width report
  • Quick output where locale does not matter
Reach for something else
  • Money arithmetic → integer minor units, or a decimal library
  • User-facing numbers → toLocaleString or Intl.NumberFormat
  • You need a number back → you probably wanted Math.round
  • Significant digits rather than decimal places → toPrecision

Notes

Complexity
O(1)
Return
A new string; the number is unchanged
CPython impl
V8: Builtins-number-tofixed
Memory
Allocates the result string
Thread-safe
Single-threaded

FAQ

Because 1.005 is not the number you think it is. Written as a double it is approximately 1.00499999999999989, which correctly rounds to 1.00. Multiply it by 1000 and you get 1004.9999999999999 — the shortfall is visible.

1.005 * 1000;   // 1004.9999999999999

History

ES3
toFixed, toPrecision and toExponential added together.
ES2012
ECMA-402 brought Intl.NumberFormat, the correct tool for user-facing numbers.