Format bytes as KB/MB/GB
Turns a raw byte count into a readable KB/MB/GB string using 1024-based units — the OS convention for file sizes, not 1000-based SI.
Last updated
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return "0 B";
const k = 1024;
const sizes = ["B", "KB", "MB", "GB", "TB", "PB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
const value = bytes / Math.pow(k, i);
return `${value.toFixed(decimals)} ${sizes[i]}`;
}
// formatBytes(1536) -> "1.50 KB"How it works
The unit index i comes from Math.log(bytes) / Math.log(1024) floored — that's just "how many times does 1024 divide into this number" without a loop. k = 1024 is a deliberate choice: file managers and OSes report sizes in binary units (a 1 MB file is 1,048,576 bytes on disk), even though drive manufacturers market capacity in 1000-based SI units. If you're matching a spec that wants SI, swap k to 1000 and relabel as KB/MB with no other change.
toFixed(decimals) is applied uniformly, including to plain bytes, so formatBytes(523) reads "523.00 B" rather than a special-cased whole number — consistent formatting beats a prettier edge case here.
Edge cases to know
- →bytes === 0 is special-cased because Math.log(0) is -Infinity, which would otherwise send the unit index out of bounds.
- →Negative byte counts aren't guarded against — Math.log of a negative number is NaN, so validate upstream if the value could come from a subtraction.
- →The sizes array tops out at PB; anything larger falls off the end and prints undefined — extend the array if you're working with exabyte-scale numbers.