filenamify
Convert any string into a valid, cross-platform safe filename in one function call.
Repository Health
Technical Analysis
filenamify is a small utility from Sindre Sorhus that takes any string — user input, a URL, a page title, an API resource name — and converts it into a filename that’s safe to write on both Unix-like systems and Windows. It strips or replaces reserved characters (< > : " / \ | ? *), removes control characters and Unicode formatting marks (while preserving the zero-width joiner needed for emoji), normalizes exotic Unicode whitespace to a plain space, and guards against Windows-reserved device names like CON or NUL by appending a replacement suffix.
Beyond simple character substitution, it handles the edge cases that trip up naive sanitizers: grapheme-aware truncation (via Intl.Segmenter) that won’t split emoji sequences, surrogate pairs, or combining characters when enforcing a maxLength; trailing dot/space stripping per Windows naming rules; and a companion filenamifyPath export that sanitizes only the basename of a full path while leaving the directory portion untouched.
What You Get
filenamify(string, options?)— the core function that sanitizes a string into a safe filename, replacing reserved characters with a configurable replacement (default!).filenamifyPath(path, options?)— resolves a path and sanitizes only its basename, then rejoins it with the original directory so the rest of the path is untouched.- A browser-only entry point (
filenamify/browser) that omits the Node.jspath-dependentfilenamifyPathexport for bundler-friendly usage. - Grapheme-aware truncation built on
Intl.Segmenterthat respects a configurablemaxLength(default 100) without splitting emoji, surrogate pairs, or combining-character sequences. - Automatic detection and disambiguation of Windows-reserved device names (
CON,NUL,PRN,COM1-COM9,LPT1-LPT9, etc.) by appending the replacement string.
Common Use Cases
- Saving user-generated content - An app that lets users name their own exports (PDFs, images, notes) runs the title through filenamify before writing to disk, so titles containing
/,:, or emoji don’t break the write or corrupt the path. - Downloading files by remote title - A scraper or download manager that names local files after a webpage title, API resource name, or email subject uses filenamify to strip characters that are illegal on the OS it’s running on.
- Cross-platform CLI tools - A build tool or CLI that writes one output file per item (per test case, per commit, per record) uses filenamify so the same tool produces valid filenames on Linux/macOS and Windows without OS-specific branching.
- Caching by derived key - A cache or asset pipeline that derives a filename from a cache key or URL uses filenamify to guarantee the derived name is filesystem-safe regardless of what characters appear in the key.
Under The Hood
Architecture
All sanitization logic lives in a single ordered pipeline inside filenamify.js: normalize to NFC, collapse Unicode whitespace, collapse repeated reserved characters, strip trailing dots/spaces, replace relative-path patterns and reserved characters (via the filename-reserved-regex dependency), strip control characters, re-strip trailing dots/spaces, fall back to the replacement string if the result is empty, truncate by grapheme budget, strip trailing dots/spaces again, and finally guard against Windows-reserved device names. filenamify-path.js is a thin wrapper that uses node:path to split a path into dirname/basename, delegates the basename to filenamify(), and rejoins the result — so both exports break identically if the core pipeline changes, by design. index.js is the single Node entry point re-exporting both; a separate filenamify/browser export exists purely to omit the node:path dependency for bundled code.
Tech Stack
Pure ESM ("type": "module") targeting Node.js >=20, with exactly one runtime dependency (filename-reserved-regex ^4.0.1) for reserved-character detection. Grapheme splitting uses the built-in Intl.Segmenter rather than a polyfill library. The exports map in package.json splits a Node-facing . entry from a ./browser entry that excludes filenamifyPath. No build or bundling step — it ships hand-written ESM source directly alongside hand-written .d.ts declaration files. Dev tooling is ava for tests and xo (an opinionated ESLint preset) for linting, both run via npm test; CI (GitHub Actions) runs that same command across a Node 20/24 matrix.
Code Quality
test.js carries extensive coverage — dozens of ava assertions across the core filenamify() behavior, filenamifyPath(), length/truncation boundary conditions, and dedicated grapheme-aware truncation cases for emoji sequences, surrogate pairs, combining characters, and regional-indicator flag emojis. Linting is enforced in CI via xo. There’s no compiled TypeScript, but hand-written .d.ts files ship with the package so consumers get full type information without a build step. Error handling is explicit rather than silent: a TypeError is thrown for non-string input, and a plain Error for a replacement string that itself contains reserved or control characters.
API Design
The public surface is deliberately minimal — one default export (a function) plus one named export for path handling — following the single-purpose, sensible-defaults style typical of Sindre Sorhus’s utility packages. Every option is optional (replacement defaults to !, maxLength defaults to 100), and the README documents exact precedence rules, such as Windows-reserved-name avoidance taking priority over the configured maxLength. The genuinely hard part this library gets right — where many ad hoc sanitizers fail — is Unicode-correct truncation that never splits an emoji or combining-character sequence mid-grapheme.
Used by 6 apps in this directory
APITable
Low Code Platforms · Databases
API-first collaborative spreadsheet-database platform that auto-generates REST APIs and lets teams build internal tools, CRMs, and dashboards without code.
Bun
Developer Tools
An all-in-one JavaScript and TypeScript toolkit — one Rust-and-JavaScriptCore binary that replaces Node.js, npm, a bundler, and a test runner with faster equivalents.
Epicenter
Knowledge Management · Note Taking · Developer Tools
A local-first monorepo led by Whispering, an open-source speech-to-text app, built on an MIT toolkit that turns your data into plain Markdown and SQLite files you own instead of a database you rent.
LibreChat
Developer Tools · AI Assistants
Unite every major AI model in one self-hosted chat platform with agents, code execution, MCP tools, and enterprise authentication.
Papra
Bookmarks Archiving
Self-hosted document archiving with email ingestion, OCR full-text search, and pluggable storage — store once, find anything.
Rocket.Chat
Team Chat
The secure, self-hosted team communications platform for organizations that cannot compromise on data sovereignty.