file naming

why

file names are the symbol table humans and agents search before opening anything: grep, tree, and go-to-definition all resolve through the basename. a vague name forces every lookup to open the file to learn what it owns; two vague names invite duplicate owners of one concept. an exact, granular basename keeps the workspace navigable without reading it.

rule

the basename alone must state the file's primary concept and required responsibility — no opening the file, no relying on its directory. one authored file owns one granular concept, behavior, rule, or outcome, in the shortest exact project-native words.

naming shape

  • data or schema: concept noun — processSnapshot.ts, processSnapshotSchema.ts.
  • boundary: exact responsibility suffix — billingChargeMapper.ts, processRouter.ts, processRepository.ts, structuredLogger.ts.
  • public operation file named for its primary exported operation when that is the only responsibility: readWorkflowStep.ts.
  • standard document named as a rule or required outcome: query-keys-have-one-owner.mdx, not query-key-ownership.mdx.
  • procedure: action and result. case study: decision and result.
  • authored asset: subject and use; never template names like file.svg or window.svg.
  • tool-required basenames stay only where the tool mandates them (page.tsx, route.ts, layout.tsx, package.json, migrations, generated artifacts) — keep them thin adapters or manifests; move real implementation into explicitly named files.

consistency

choose casing by responsibility, then apply it consistently:

casingowns
PascalCaseAuthored React components, contexts, and providers: WorkflowPanel.tsx, ProcessContext.tsx, ProcessProvider.tsx.
camelCaseAuthored TypeScript behavior, hooks, schemas, mappers, routes, repositories, and services: readWorkflowStep.ts, useWorkflowTree.ts, processSnapshotSchema.ts.
snake_casedatabase tables, columns, constraints, and SQL-owned migration identifiers: workflow_step, process_id.
kebab-caseshadcn/ui component filenames required by that ecosystem: alert-dialog.tsx, dropdown-menu.tsx.

never derive a filename by casing or rewriting a display label; store the canonical technical name directly. the exported symbol uses the same semantic words, no second alias.

selection process

  1. find the canonical domain noun in the glossary.
  2. name the file's one primary responsibility: render, read, map, validate, persist, route, integrate, enforce, or prove.
  3. apply the casing required by that responsibility and ecosystem boundary.
  4. compare the file name with its primary export — same exact concept, no alias.
  5. read the basename without its path; it must still state concept and responsibility.
  6. search for an existing file owning the same noun/responsibility pair before creating another.

verification

  • read basenames without paths; each should answer what the file owns and what it requires or does.
  • each exported public symbol should be discoverable through the same words.
  • after a rename, search for generic buckets and retired names; move or delete them so they do not become alternate navigation paths.

good and bad

bad

utils.ts
helpers.ts
processstuff.ts // casing-rewritten display label
database-design.mdx // topic only; no required direction

generic buckets and casing-derived names hide ownership, so tree search fails. "where is normalizeDate used?" means opening utils.ts, helpers.ts, and common.ts in turn instead of finding dateUtils.ts immediately. a single utils.ts sprawls to 500 lines into a junk drawer. "show me what schema validation exists" returns nothing because schemas hide in files with no naming clue.

good

processSnapshotSchema.ts // concept noun, camelCase behavior
billingChargeMapper.ts // exact responsibility suffix
WorkflowPanel.tsx // PascalCase authored component
query-keys-have-one-owner.mdx // subject plus required direction

each name states one concept with responsibility-chosen casing, so tree reveals the concepts: searching "schema" finds processSnapshotSchema.ts immediately; find . -name "*Mapper*" lists every mapper; readUserPreferences.ts and readWorkflowProgress.ts answer "what data does this service read" unopened.

do not

  • use utils, helpers, common, types, constants, manager, service, or data as a catch-all authored filename. index.ts is reserved solely for a pure folder barrel under the nesting structure rule.
  • name a file after a vendor, screen, temporary implementation, or stale migration path when the domain responsibility has a stable name.
  • use a topic-only document filename that does not state its rule, action, or outcome.
  • put two independently understandable routes, schemas, mappers, or workflows in one file merely because their names share a prefix.

search pages

go to any page