---
title: "Naming Conventions"
slug: "naming-conventions"
category: "file-organization"
tags: ["file-organization", "naming", "conventions", "kebab-case"]
status: "stable"
last_updated: 2026-05-14
summary: "kebab-case files, snake_case Python, camelCase JS; no abbreviations of domain nouns; name intent, not implementation."
related: ["[[file-organization/folder-hierarchy]]", "[[file-organization/project-structure]]", "[[file-organization/config-files]]", "[[coding/general-principles]]", "[[tooling/obsidian]]"]
---

## Overview

A filename is a tiny piece of API. It is the thing people type, grep, and link to. The rules below pick one casing per ecosystem, ban domain-noun abbreviations, anchor dates in ISO, and resolve filename collisions. They follow the same logic as [[coding/general-principles]]: a good name kills its own comment.

## kebab-case for files unless the language says otherwise

Use lowercase, hyphen-separated filenames by default. They survive case-insensitive filesystems, URL slugs, and shell tab completion without quoting.

- Markdown, HTML, config: `naming-conventions.md`, `index.html`, `pre-commit-config.yaml`.
- Static assets: `hero-image.png`, `favicon-32.png`.
- Top-level project files keep their canonical names: `README.md`, `LICENSE`, `Dockerfile`.

The exceptions are languages whose tooling expects a specific case. Honor the toolchain; do not fight it.

- **Python:** `snake_case.py`. Module names map to import paths; hyphens are illegal in identifiers.
- **JavaScript / TypeScript files:** `camelCase.ts` for modules, `PascalCase.tsx` for React components. Some teams use `kebab-case.ts` for non-component files; pick one and document it.
- **Rust:** `snake_case.rs`. Crate names use kebab-case in `Cargo.toml`, snake_case as the import.
- **Go:** `lowercase.go` or `snake_case_test.go`. No camelCase, no hyphens.
- **Swift:** `PascalCase.swift` for type files (`UserProfile.swift`).

## Name describes intent, not implementation

The filename should tell the reader what role the file plays, not how it does it.

- `invoice-parser.ts`, not `xml-utils.ts`. Two months from now the implementation might be JSON; the role does not change.
- `auth-middleware.py`, not `decorator.py`. "Decorator" describes how, not what.
- `daily-report.sql`, not `query-3.sql`. The role survives a rewrite.

A filename that names the implementation is a refactor away from being a lie. Name the responsibility.

## Never abbreviate domain nouns

The five-character savings cost a lookup every time a new reader hits the file. Spell it out.

- `customer.ts`, not `cust.ts`.
- `subscription-renewal.py`, not `sub-ren.py`.
- `pull-request-review.md`, not `pr-rvw.md`.

The exceptions are abbreviations the field already settled on:

- `id`, `url`, `uri`, `http`, `db`, `api`, `dto`, `json`, `xml`, `csv`.

If a reader has to ask "what does `mgr` stand for?" once, the name failed. Match the spelling to the domain language used in tickets and docs.

## ISO dates in filenames

Dates in filenames are sortable when they use ISO 8601: `YYYY-MM-DD`.

```
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
```

Avoid `05-14-2026`, `14-may-2026`, or `today.sql`. None of them sort. ISO times use `T` and either `-` or `:` (filesystems on Windows ban `:`); pick `-` and keep the format consistent. See [[file-organization/folder-hierarchy]] for date-partitioned directories.

## Resolve filename collisions with paths, not numbers

Two files named `utils.ts` in different folders are fine until someone greps. Add a path-distinct prefix or rename to something specific.

- Prefer renaming: `string-utils.ts` and `date-utils.ts` instead of two `utils.ts`.
- When a rename is impossible (framework convention), keep the names and rely on the folder path for disambiguation: `pages/blog/index.tsx` and `pages/about/index.tsx`.
- Never resolve a collision with a numeric suffix (`utils-2.ts`). The number tells the reader nothing about which utils it holds.

In Obsidian and Quartz, slug collisions force folder-prefixed wikilinks (`[[seo/technical]]` vs `[[frontend/technical]]`). See [[tooling/obsidian]].

## Plural vs singular: pick by what the file holds

A file holds one thing or many. Match the noun number.

- `user.ts` exports a `User` type; `users.ts` holds a collection or a CRUD module for users.
- `route.ts` defines one route; `routes.ts` registers many.
- React component files are singular by convention: `UserCard.tsx`, not `UserCards.tsx`, even if the component renders a list.

Folders follow the same rule: `migrations/` (a folder of many migrations), `config/` (a folder of one config split into pieces).

## Test files mirror the source name

A test file's name should make the source file obvious.

- Python: `test_invoice.py` for `invoice.py`. Pytest discovers it automatically.
- JS/TS: `invoice.test.ts` or `invoice.spec.ts` next to `invoice.ts`. Pick one suffix and stick with it.
- Go: `invoice_test.go` next to `invoice.go`. The `_test.go` suffix is mandatory; Go's toolchain uses it for collection.
- Swift: `InvoiceTests.swift` for `Invoice.swift`.

A test file that does not mirror its source name will eventually drift away from it. See [[coding/testing]].

## Related

- [[file-organization/folder-hierarchy]]
- [[file-organization/project-structure]]
- [[file-organization/config-files]]
- [[coding/general-principles]]
- [[tooling/obsidian]]
