Overview
A filename is a small API: people type it, grep it, and link to it. The rules below pick one casing per ecosystem, name files by role, ban abbreviated domain nouns, require ISO dates, and resolve collisions without numeric suffixes.
Default to kebab-case
Lowercase and hyphen-separated names survive case-insensitive filesystems, URL slugs, and tab completion without quoting.
- Docs, HTML, config:
naming-conventions.md,index.html,pre-commit-config.yaml. - Assets:
hero-image.png,favicon-32.png. - Canonical project files keep their names:
README.md,LICENSE,Dockerfile.
Follow the language where its tooling expects a case:
- Python:
snake_case.py. Hyphens are illegal in import identifiers. - Rust:
snake_case.rs. Crate names use kebab-case inCargo.tomland snake_case in code. - Go: lowercase. An underscore suffix means something to the toolchain (
_test.go,_linux.gobuild constraints), so do not add underscores casually. - JavaScript and TypeScript:
PascalCase.tsxfor React components. For other modules choosecamelCase.tsorkebab-case.tsand document the choice. - Swift:
PascalCase.swiftfor type files, such asUserProfile.swift.
Name the role, not the implementation
invoice-parser.ts, notxml-utils.ts: the format may change; the role will not.auth-middleware.py, notdecorator.py.daily-report.sql, notquery-3.sql.
A name that describes the implementation is one refactor from being a lie.
Spell out domain nouns
Write customer.ts, subscription-renewal.py, pull-request-review.md. Abbreviations the field already settled on are fine: id, url, uri, http, db, api, dto, json, xml, csv. Match the spelling used in tickets and docs.
Write dates as ISO 8601
YYYY-MM-DD sorts correctly; 05-14-2026 and 14-may-2026 do not.
posts/2026-05-14-quartz-release-notes.md
migrations/2026-03-01-add-user-index.sql
backups/db-2026-05-14T03-00-00Z.sql.gz
Windows forbids : in filenames, so use - in times and keep the format fixed.
Resolve collisions with names, not numbers
Rename duplicates to something specific: string-utils.ts and date-utils.ts instead of two utils.ts. When a framework dictates the name (pages/blog/index.tsx, pages/about/index.tsx), let the path disambiguate. Never use utils-2.ts.
In Obsidian and Quartz, shared filenames force folder-prefixed wikilinks; see obsidian.
Match singular and plural to the contents
user.ts exports one User type; users.ts holds a collection or CRUD for users. route.ts defines one route, routes.ts registers many. React component files stay singular (UserCard.tsx) even when they render a list. Folders follow the same rule: migrations/ holds many.
Mirror source names in test files
- Python:
test_invoice.pyforinvoice.py; pytest discovers it. - JavaScript and TypeScript:
invoice.test.tsorinvoice.spec.tsnext to the source; pick one suffix. - Go:
invoice_test.go; the suffix is mandatory. - Swift:
InvoiceTests.swiftforInvoice.swift.
A test that does not mirror its source name drifts away from it. See testing.