byte-size
Converts a numeric bytes value into a human-readable string like '3.5 kB', with metric, IEC, and fully custom unit support.
Repository Health
Technical Analysis
byte-size is a small isomorphic JavaScript function that turns a raw bytes count (e.g. 3456) into a readable string such as ‘3.5 kB’. It ships built-in metric, metric-octet, IEC, and IEC-octet unit tables, and lets you define entirely custom unit tables and formatting for cases the built-ins don’t cover.
The library has no runtime dependencies, works unmodified in Node.js, browsers, and any ES module loader, and exposes a single function whose returned object implements toString, so results can be dropped directly into template strings or logs.
What You Get
- A single dependency-free function, byteSize(bytes, options), importable via CommonJS, ESM, or a browser <script> global.
- Four built-in unit tables - metric, metric_octet, iec, and iec_octet - covering both decimal (1000-based) and binary (1024-based) byte conventions.
- Configurable precision, locale-aware number formatting via Intl.NumberFormat, and a pluggable toStringFn for custom output formats.
- Support for fully custom unit tables via options.customUnits, plus byteSize.defaultOptions() to set process-wide defaults once.
Common Use Cases
- Displaying file or upload sizes in a UI (e.g. ‘12.4 kB’ next to a file name).
- Formatting disk usage, memory, or bandwidth figures in CLI tool output.
- Logging response payload or request body sizes in human-readable form in server logs.
- Building custom size units (e.g. simplified ‘K’/‘M’/‘B’ notation) for domain-specific dashboards.
Under The Hood
Architecture The whole library is a single ES module (index.js, ~120 lines) exporting one function, byteSize, backed by a private ByteSize class. State is minimal: a module-level defaultOptions object and a WeakMap (_options) associating each instance with its resolved options, keeping instance internals out of enumerable properties. Construction runs synchronously: options are merged (call-site overrides over process-wide defaultOptions over library defaults), any customUnits are merged into the shared referenceTables object, then the correct unit-table row is located via Array.find against from/to ranges and formatted through Intl.NumberFormat. There are no external calls, no I/O, and no async paths - the entire data flow is a single pure transform from (bytes, options) to a value/unit/long triple with a toString method. Because referenceTables is a single shared, mutable object at module scope, calling byteSize anywhere in a process with customUnits permanently mutates the shared tables for all subsequent calls, which is the one non-obvious coupling in an otherwise flat, single-file design.
Tech Stack The package has zero runtime dependencies; package.json lists only a single optional peer dependency, @75lb/nature, which supplies the maintainer’s own build/test/docs toolchain (a test runner, jsdoc-to-markdown, and a CommonJS bundler) but is never required by consumers. Source ships as a native ES module (“type”: “module”), and package.json’s exports map provides a prebuilt dist/index.cjs for CommonJS require() callers alongside the ESM index.js, so both module systems get a working entry point without a consumer-side build step. CI runs the test suite across a wide range of Node versions on Ubuntu, confirming the isomorphic, no-transpilation claim. There is no framework, database, or deployment target involved - it’s a pure utility function distributed as flat files.
Code Quality Tests live in a single test.js using a lightweight Map-based test registry exercised by the maintainer’s own test-runner package rather than a mainstream framework like Jest or Vitest; assertions use Node’s built-in assert.strict. Coverage is thorough for a library this size - cases across all four unit tables, negative numbers, boundary values, precision options, custom toStringFn, custom units, and locale formatting are all exercised directly against the public entry point. Error handling is minimal by design: an invalid options.units throws a plain, descriptive Error, and there are no silent failures in the reviewed code path. Naming is consistent and short, the code has no TypeScript types (plain JS with JSDoc comments powering the generated API docs in README.md), and linting follows the standard style with dist/ excluded. CI runs the suite across many Node versions on every push and pull request, giving reasonable confidence despite no visible coverage tooling.
API Design The public surface is a single function call, byteSize(bytes, options), with sensible zero-config defaults (metric units, precision 1), which makes the common case a one-liner; the returned object’s toString() method means results drop directly into template literals without explicit value/unit concatenation, a small but genuinely convenience-focused touch. Optional power-user features (custom unit tables, custom toStringFn, locale passthrough, process-wide defaultOptions()) are additive and don’t complicate the basic call. Documentation is strong for a small library: the README enumerates every built-in unit table in full, gives runnable synopsis examples for each option, and the JSDoc comments in index.js are the literal source for the generated API reference section, so docs and implementation cannot drift independently. The main rough edge is the shared-mutable-table behavior of customUnits, which isn’t called out prominently in the README relative to its process-wide side effect.
Used by 3 apps in this directory
DefGuard
Security · Networking · Authentication
Self-hosted secure remote access that unifies WireGuard VPN, identity management, and connection-level MFA in one open-source platform.
Kibana
Analytics · Monitoring
Your open source window into the Elastic Stack — query, visualize, and act on data stored in Elasticsearch with real-time dashboards, AI-assisted search, and automated alerting.
strapi
CMS
Open-source headless CMS that auto-generates REST and GraphQL APIs from your content models, with a fully customizable admin panel you control.