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 in Cargo.toml and snake_case in code.
  • Go: lowercase. An underscore suffix means something to the toolchain (_test.go, _linux.go build constraints), so do not add underscores casually.
  • JavaScript and TypeScript: PascalCase.tsx for React components. For other modules choose camelCase.ts or kebab-case.ts and document the choice.
  • Swift: PascalCase.swift for type files, such as UserProfile.swift.

Name the role, not the implementation

  • invoice-parser.ts, not xml-utils.ts: the format may change; the role will not.
  • auth-middleware.py, not decorator.py.
  • daily-report.sql, not query-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.py for invoice.py; pytest discovers it.
  • JavaScript and TypeScript: invoice.test.ts or invoice.spec.ts next to the source; pick one suffix.
  • Go: invoice_test.go; the suffix is mandatory.
  • Swift: InvoiceTests.swift for Invoice.swift.

A test that does not mirror its source name drifts away from it. See testing.