RepoPilotOpen in app →

sindresorhus/pretty-bytes

Convert bytes to a human readable string: 1337 → 1.34 kB

WAIT

Slowing — last commit 8mo ago

worst-case
Use as dependencyGO

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyGO

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromGO

Documented and popular — useful reference codebase to read through.

Deploy as-isWAIT

last commit was 8mo ago; Scorecard "Branch-Protection" is 0/10…

  • Last commit 8mo ago
  • 5 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • Slowing — last commit 8mo ago
  • Small team — 5 top contributors
  • Single-maintainer risk — top contributor 88% of commits
  • Scorecard: marked unmaintained (0/10)
  • Scorecard: default branch unprotected (0/10)
What would change the verdict?
  • Deploy as-is WAITGO if: 1 commit in the last 180 days; bring "Branch-Protection" to ≥3/10 (see scorecard report)

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests + OpenSSF Scorecard

Embed this verdict

[![RepoPilot: WAIT](https://repopilot.app/api/badge/sindresorhus/pretty-bytes)](https://repopilot.app/r/sindresorhus/pretty-bytes)

Paste into your README — the badge live-updates from the latest cached analysis.

Onboarding doc

Onboarding: sindresorhus/pretty-bytes

Generated by RepoPilot · 2026-05-05 · Source

Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/sindresorhus/pretty-bytes shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

Verdict

WAIT — Slowing — last commit 8mo ago

  • Last commit 8mo ago
  • 5 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Slowing — last commit 8mo ago
  • ⚠ Small team — 5 top contributors
  • ⚠ Single-maintainer risk — top contributor 88% of commits
  • ⚠ Scorecard: marked unmaintained (0/10)
  • ⚠ Scorecard: default branch unprotected (0/10)

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests + OpenSSF Scorecard</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live sindresorhus/pretty-bytes repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/sindresorhus/pretty-bytes.

What it runs against: a local clone of sindresorhus/pretty-bytes — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in sindresorhus/pretty-bytes | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 256 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>sindresorhus/pretty-bytes</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of sindresorhus/pretty-bytes. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/sindresorhus/pretty-bytes.git
#   cd pretty-bytes
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of sindresorhus/pretty-bytes and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "sindresorhus/pretty-bytes(\\.git)?\\b" \\
  && ok "origin remote is sindresorhus/pretty-bytes" \\
  || miss "origin remote is not sindresorhus/pretty-bytes (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "index.js" \\
  && ok "index.js" \\
  || miss "missing critical file: index.js"
test -f "index.d.ts" \\
  && ok "index.d.ts" \\
  || miss "missing critical file: index.d.ts"
test -f "package.json" \\
  && ok "package.json" \\
  || miss "missing critical file: package.json"
test -f "test.js" \\
  && ok "test.js" \\
  || miss "missing critical file: test.js"
test -f "readme.md" \\
  && ok "readme.md" \\
  || miss "missing critical file: readme.md"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 256 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~226d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/sindresorhus/pretty-bytes"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

A lightweight utility that converts byte counts into human-readable strings using SI prefixes (base-10, e.g. 1337 bytes → '1.34 kB'). It supports binary prefixes (base-2 for KiB/MiB), bit formatting, locale-aware number formatting, and signed output for displaying file size differences. Written as a pure ESM module with TypeScript type definitions. Single-file ESM module: index.js exports one default function prettyBytes(), with type definitions in index.d.ts. No monorepo structure; test suite in test.js covers all functionality. Includes TypeScript definition tests (index.test-d.ts) to validate type definitions match implementation.

Who it's for

Frontend and backend developers building file upload interfaces, progress displays, storage dashboards, or system monitoring tools who need quick byte-to-human conversion without external dependencies. Used by library maintainers who need this functionality in their own packages (it's a dependency of other npm packages).

Maturity & risk

Production-ready and actively maintained. Version 7.1.0 with Node ≥20 requirement indicates modern maintenance. Contains comprehensive test coverage (test.js) and TypeScript definitions (index.d.ts), with CI/CD via GitHub Actions (main.yml). Single maintainer (Sindre Sorhus) but well-established with stable API.

Standard open source risks apply.

Active areas of work

No active development signals visible in the provided data (no PR/issue counts, commit recency, or milestone information). The package appears stable and feature-complete at v7.1.0 with no breaking changes mentioned.

Get running

git clone https://github.com/sindresorhus/pretty-bytes.git
cd pretty-bytes
npm install
npm test

Daily commands:

npm test

Runs: xo (linting), ava (unit tests in test.js), and tsd (TypeScript definition tests in index.test-d.ts).

Map of the codebase

  • index.js — Core entry point implementing the byte-to-human-readable conversion algorithm with locale and formatting support; all functionality flows through here.
  • index.d.ts — TypeScript type definitions defining the public API contract; required for type safety and IDE autocomplete in consuming projects.
  • package.json — Package metadata, ESM export configuration, and Node 20+ engine requirement; critical for correct module resolution and runtime compatibility.
  • test.js — Test suite validating all options (signed, bits, locale, fixedWidth) and edge cases; ensures behavior stability across releases.
  • readme.md — API documentation and usage examples; primary reference for understanding function signature, options, and locale behavior.

Components & responsibilities

  • prettyBytes() function (JavaScript, Intl.NumberFormat) — Main export; accepts number/bigint and options object; orchestrates conversion, locale formatting, and output styling
    • Failure mode: Returns NaN or throws if input is invalid; incorrect locale throws from Intl; fixedWidth overflow not truncated
  • Unit conversion logic (JavaScript math, array iteration) — Determines correct unit (B, kB, MB, etc.) by iterating UNITS and comparing against threshold; calculates scaled value
    • Failure mode: Very large numbers may exceed largest unit (EB); precision loss for very small fractional values
  • Locale formatting (Intl.NumberFormat API) — Delegates number formatting to Intl.NumberFormat for decimal separator and digit grouping per locale
    • Failure mode: Unsupported locale codes silently default to 'en-US'; some locales may not have expected separators
  • Sign and padding logic (String manipulation, padding) — Prepends sign character (+ or −) if signed option is true; left-pads with spaces to fixedWidth if specified
    • Failure mode: fixedWidth not respected if output exceeds width; no truncation occurs

Data flow

  • CallerprettyBytes() — Input: number/bigint and optional options object (signed, bits, locale, fixedWidth)
  • prettyBytes()Unit conversion — Determines scale and unit based on input value magnitude
  • Unit conversionIntl.NumberFormat — Passes scaled numeric value and locale to Intl for localized formatting
  • Intl.NumberFormatprettyBytes() — Returns locale-formatted number string (e.g., '1,34' in de-DE)
  • prettyBytes()Sign/padding logic — Applies sign prefix and fixedWidth padding to formatted string
  • Sign/padding logicCaller — Output: human-readable byte string (e.g., '+1.34 kB', ' 1.34 kB')

How to make changes

Add a new formatting option

  1. Add the new option property to the TypeScript interface in index.d.ts (e.g., maximumFractionDigits?: number) (index.d.ts)
  2. Implement the logic in index.js to read and apply the new option in the formatting algorithm (index.js)
  3. Add test cases in test.js covering the new option with various inputs and edge cases (test.js)
  4. Add usage example and documentation to readme.md showing the new option in action (readme.md)

Add support for a new locale

  1. The locale option is already implemented in index.js using Intl.NumberFormat; add test case in test.js with the new locale code (test.js)
  2. Run tests to validate the locale is correctly formatted by the native Intl API (test.js)

Modify unit conversion thresholds or units list

  1. Edit index.js where the UNITS array or conversion constants are defined (kB, MB, GB, etc. progression) (index.js)
  2. Update test.js with test cases reflecting the new thresholds and unit boundaries (test.js)
  3. Document the change in readme.md if it affects user-visible behavior (readme.md)

Why these technologies

  • ECMAScript Module (ESM) — Modern JavaScript module system with explicit exports; enables tree-shaking and is the standard for contemporary npm packages.
  • Intl.NumberFormat — Native browser/Node API for locale-aware number formatting; eliminates dependency on external locale libraries and provides accurate localization.
  • TypeScript — Provides type safety and IntelliSense for consumers; tsd validates type definitions match implementation at build time.
  • ava + xo — ava provides isolated test execution; xo enforces consistent code style. Together they ensure quality and maintainability with minimal configuration.

Trade-offs already made

  • Base-10 units (kB, MB) instead of binary units (KiB, MiB)

    • Why: Simpler, more familiar to end users; matches SI standard and common usage.
    • Consequence: Users comparing file sizes to OS tools that use base-2 will see different numbers; readme clarifies this and links to explanation.
  • Locale formatting via Intl.NumberFormat rather than custom rules

    • Why: Avoids maintaining a locale-specific rules database and leverages native APIs.
    • Consequence: Locale support is limited to what Node.js/browser Intl supports; edge cases in rare locales may not format perfectly.
  • Single zero-dependency module

    • Why: Minimizes bundle size and external risk; package is small and focused.
    • Consequence: Cannot delegate formatting; must implement locale handling directly via Intl.
  • Node 20+ engine requirement

    • Why: Ensures modern JavaScript features and stable Intl implementation.
    • Consequence: Users on Node <20 cannot use this version; would need to use older releases.

Non-goals (don't propose these)

  • Does not handle binary (base-2) units like KiB, MiB — only decimal SI units
  • Does not provide reverse conversion (human string back to bytes)
  • Not a real-time or streaming formatter — processes a single number per call
  • Does not provide custom unit lists or thresholds via options
  • Does not handle negative bigint values in all locales (edge case per Node.js Intl)

Anti-patterns to avoid

  • Hardcoded unit thresholds (Low)index.js (UNITS array logic): Unit progression (B → kB → MB → GB → TB → PB → EB) is fixed in code; adding custom units or thresholds requires code modification rather than configuration.
  • Silent locale fallback (Low)index.js (Intl.NumberFormat instantiation): Invalid locale codes do not throw; Intl silently uses en-US fallback, potentially masking configuration errors.
  • No input validation messaging (Medium)index.js: Invalid inputs (e.g., non-numeric types) cause Intl errors rather than descriptive validation messages; error context is lost.

Performance hotspots

  • index.js (unit loop) (Algorithm efficiency) — Iterates through UNITS array until threshold is exceeded; worst case O(n) where n=9 units. Negligible for typical inputs but not memoized.
  • Intl.NumberFormat instantiation (Runtime performance (microsecond-level)) — Creating a new Intl.NumberFormat instance per call; could be cached by locale for repeated calls with same locale.

Traps & gotchas

None obvious from provided data. Module is straightforward: ESM-only (no CommonJS), Node 20+ only (uses modern Intl API). No environment variables, external services, or config files required. The locale option uses browser/Node Intl.NumberFormat, so ensure test environment has locale data available (typically standard in modern Node.js).

Architecture

Concepts to learn

  • SI Prefix (base-10) — pretty-bytes defaults to SI prefixes (kB, MB, GB where 1 kB = 1000 bytes) as opposed to binary prefixes; understanding this distinction is critical for choosing the right output format
  • Binary Prefix (base-2) — The binary option switches to KiB/MiB/GiB (where 1 KiB = 1024 bytes), essential for displaying memory usage accurately; this repo lets users toggle between both standards
  • Intl.NumberFormat API — pretty-bytes uses this modern Web API for locale-aware number formatting (decimal separators, thousand separators); understanding it helps modify localization behavior
  • Significant Figures — The default behavior rounds to 3 significant digits (e.g., 1.34 kB); the repo trades off between readability and precision, tunable via minimumFractionDigits/maximumFractionDigits
  • Truncation vs. Rounding — When minimumFractionDigits/maximumFractionDigits are set, values are truncated rather than rounded for 'more intuitive' output; this design choice affects test expectations and user-facing behavior
  • ESM (ECMAScript Modules) — pretty-bytes is ESM-only (no CommonJS fallback); contributors must understand import/export syntax and Node.js ESM handling, including the 'type': 'module' package.json directive
  • BigInt Type Support — The function accepts both number and bigint inputs for handling arbitrarily large byte counts; this requires conditional logic and type checking not obvious in a simple number→string converter

Related repos

  • yg/filesize — Alternative bytes-to-human conversion library with support for more formats (metric, IEC, SI) and more configuration options
  • evgenyneu/js-file-download — Pairs with pretty-bytes: handles file downloads while pretty-bytes displays the file size to users
  • sindresorhus/bytes-to-string — Similar conversion concept for different unit systems (temperature, distance); shows pattern of small, focused utilities by same maintainer
  • sindresorhus/parse-bytes — Inverse operation: parses human-readable strings like '1.34 kB' back into byte counts, complementing pretty-bytes for two-way conversion

PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive test coverage for edge cases in index.test-d.ts

The TypeScript definition file (index.d.ts) exports type definitions for prettyBytes with various options (bits, signed, fixedWidth, locale), but the TypeScript tests in index.test-d.ts likely lack comprehensive type assertion tests. This ensures the type definitions match the actual implementation and catch type-related regressions early.

  • [ ] Review index.d.ts to identify all exported types and option combinations
  • [ ] Add type assertion tests in index.test-d.ts for bigint parameter support
  • [ ] Add type assertion tests for all options combinations (bits + signed, bits + locale, fixedWidth with other options)
  • [ ] Add type assertion tests to ensure invalid option combinations are caught by TypeScript
  • [ ] Run 'npm run test' to verify all type tests pass with tsd

Add unit tests for locale-specific formatting in test.js

The README demonstrates locale support (e.g., German with 'de' locale producing '1,34 kB'), but test.js likely lacks comprehensive locale-specific test cases. This is critical to ensure internationalization doesn't regress and handles edge cases across different locales.

  • [ ] Review test.js to identify existing locale tests
  • [ ] Add test cases for multiple locales (at least 'de', 'fr', 'es') with number/decimal separators
  • [ ] Add tests for locale-specific decimal formatting (comma vs period)
  • [ ] Add edge case tests: very large numbers with locale, negative numbers with locale
  • [ ] Run 'npm test' to ensure all tests pass

Add test cases for signed option combinations in test.js

The README shows the signed option produces '+42 B' format, but test.js may lack comprehensive coverage of signed format with other options (like bits, locale, fixedWidth). This ensures the feature behaves correctly in all scenarios.

  • [ ] Review test.js for existing signed option test coverage
  • [ ] Add tests for signed + bits combination (e.g., '+1.34 kbit')
  • [ ] Add tests for signed + fixedWidth combination with positive and negative values
  • [ ] Add tests for signed + locale combination across multiple locales
  • [ ] Add edge case: signed option with zero value (should it be '+0 B' or '0 B'?)
  • [ ] Run 'npm test' to verify all tests pass

Good first issues

  • Add tests for edge case combinations (e.g., simultaneous use of signed: true, binary: true, and locale: 'de') in test.js to improve coverage
  • Create a simple CLI wrapper that reads file paths and outputs pretty-bytes output (currently only exported as library), useful for shell scripting and could live as an example
  • Add minimumFractionDigits and maximumFractionDigits tests to index.test-d.ts to verify TypeScript correctly validates these new options with various numeric inputs

Top contributors

Recent commits

  • b7849f7 — 7.1.0 (sindresorhus)
  • 73df489 — Add fixedWidth option for right-aligned output (sindresorhus)
  • b64cee5 — Fix truncation behavior with fraction digits options (sindresorhus)
  • b637640 — Add nonBreakingSpace option (sindresorhus)
  • 3c77fd1 — 7.0.1 (sindresorhus)
  • c9fd951 — Fix precision with the binary option (#88) (siddhant-nair)
  • 4186190 — Fix CI (sindresorhus)
  • 2658a8e — 7.0.0 (sindresorhus)
  • 13d3727 — Require Node.js 20 (sindresorhus)
  • 386b35a — Add support for BigInt (#85) (kikar)

Security observations

This is a lightweight utility package with excellent security posture. No critical or high-severity vulnerabilities detected. The codebase has minimal dependencies (only dev dependencies for linting/testing), reducing attack surface. No hardcoded secrets, injection risks, or infrastructure misconfigurations identified. The package follows secure defaults with 'sideEffects: false' and proper module exports. The single low-severity issue relates to Node.js version specification flexibility rather than actual security flaws. The package appears well-maintained by a trusted author (Sindre Sorhus) with proper testing and linting in place.

  • Low · Permissive Node.js Engine Requirement — package.json - engines field. The package specifies 'node': '>=20' which allows any Node.js version 20 or higher. While this is reasonable for a small utility, it means users on unpatched or vulnerable Node.js versions could use this package without awareness. Fix: Consider specifying a more recent minimum version (e.g., '>=20.10.0') to encourage users to run patched Node.js versions. Document the minimum required version in README.

LLM-derived; treat as a starting point, not a security audit.

Where to read next


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.