Concept of the skill
What it is: Naming conventions are the rules that make artifact names truthful, predictable, and searchable across code, routes, data, configuration, and documentation-adjacent developer surfaces.
Mental model: A name is a compact contract: artifact kind decides casing, grammar decides the role of each word, and verbs/nouns promise behavior. A good name lets the reader infer what the artifact does before opening the implementation.
Why it exists: Names are read far more often than they are written. Choosing them deliberately prevents hidden cost: stale domain words, false verb promises, casing inconsistency, and missed references during renames.
What it is NOT: It is not whole-code refactoring, whole-diff code review, prose style guidance, product microcopy, or debugging a failed behavior after the name has already misled someone.
Adjacent concepts: Semantics, linguistics, refactor, code-review, debugging, version-control, and information architecture.
One-line analogy: Naming is like labeling circuit breakers: a short label is useful only when it truthfully names the circuit it controls.
Common misconception: Naming is not cosmetic. A misleading identifier creates a wrong model in every caller and reader, even when the code compiles.
Naming Conventions
Coverage
- Identifier morphology: verb-noun selection (
get vs fetch vs load), plural vs singular for collections, prefix/suffix conventions (is / has / should for booleans, use for React hooks)
- Casing per artifact kind: kebab-case (file names, URL paths, CLI flags), camelCase (JavaScript/TypeScript variables and functions), PascalCase (types, classes, components, React JSX), snake_case (Python, SQL columns, environment variables when convention demands), SCREAMING_SNAKE_CASE (constants, env-var keys)
- Abbreviation rules: when an abbreviation is universally known (
url, id, api), when it requires expansion (cust → customer), and when team-internal jargon must be avoided in public-facing names
- Name-vs-path semantics: the difference between what an artifact is called and where it lives; when name and path agree (file system) vs when they diverge (TypeScript module re-exports, npm-published package paths)
- Rename coordination: how to update every reference in the same commit, when to ship a deprecation alias, and how to detect missed call sites with grep
- Names that lie: identifiers whose words promise a behaviour the code does not deliver, and how to detect them (the function called
getX that also writes; the boolean called isReady that means "should be ready"; the column called created that stores the ship date)
- Cross-cutting consistency: when a naming choice in one part of the codebase forces a related choice elsewhere (table column
customer_id and TypeScript type Customer.id)
Philosophy of the skill
Names are the most-read part of any codebase. Every reader pays the cost of a bad name; only the author pays the cost of choosing well. The single most valuable property of a name is truthfulness: a name that lies — about what an artifact does, returns, or means — is more harmful than a name that is merely unclear. The second-most-valuable property is consistency with sibling names: a function called getOrders should sit alongside getCustomers, not loadCustomers. The third is brevity, and only the third — short names that mislead are not a virtue.
When a name does not fit, the answer is almost always to rename, not to add a comment explaining what the name "really" means. Comments rot; renames travel with the code.
Casing per Artifact Kind
Casing is project-convention-driven for the artifacts where languages don't enforce it, and language-mandated for the rest. Pick the convention once, document it in the project's CONTRIBUTING or AGENTS file, and apply it everywhere.
| Artifact |
Convention |
Example |
| File name (any) |
kebab-case |
order-pricing.ts, webhook-handler.py |
| URL path segment |
kebab-case |
/api/order-pricing |
| CLI flag |
kebab-case |
--include-template |
| JS/TS variable, function, parameter |
camelCase |
orderTotal, calculateMargin() |
| JS/TS type, class, interface, React component |
PascalCase |
Order, OrderPricing, <OrderRow/> |
| Python variable, function |
snake_case |
order_total, calculate_margin |
| Python class |
PascalCase |
Order, OrderPricing |
| SQL table name |
snake_case (lowercase) |
orders, order_line_items |
| SQL column name |
snake_case |
created_at, customer_id |
| Environment variable |
SCREAMING_SNAKE_CASE |
STRIPE_SECRET_KEY, NODE_ENV |
| Constant in code |
SCREAMING_SNAKE_CASE |
MAX_RETRIES, DEFAULT_TIMEOUT_MS |
| Boolean variable / function |
is* / has* / should* / can* prefix |
isAdmin, hasReceipt, shouldRetry |
| React hook |
use* prefix (mandatory) |
useOrders, useDebounce |
| Predicate function |
verb in interrogative form |
validateEmail(), isValidEmail() |
Identifier Morphology
The verb you pick encodes a contract. Choose deliberately.
| Verb |
Implies |
Wrong when |
get |
Pure read; cheap; never mutates; idempotent |
The function writes, calls an API, or has any side effect |
fetch |
Network or I/O read; may fail; may be slow |
The function reads from local memory or never crosses a boundary |
load |
Read-and-cache, or read-from-disk; one-shot |
The function returns synchronously from already-loaded data |
compute / calculate |
Pure transformation of inputs |
The function takes no inputs or returns I/O |
validate |
Returns boolean OR throws; no side effects |
The function modifies the input or has hidden side effects |
assert |
Throws on failure; void return on success |
The function returns a value or has a happy non-throwing path |
parse |
String → structured data; may throw on malformed input |
The function takes structured data or never throws |
format |
Structured data → string |
The function returns structured data |
create |
Allocates/persists a new entity; returns its identity |
The function returns a transient value with no persisted identity |
update |
Modifies an existing entity by identity |
The function inserts or replaces |
delete / remove |
Removes an entity from the system |
The function only removes from a transient view |
The single most common naming bug is getX that also writes. If the function has a side effect, the verb must be one that implies side effects (save, apply, commit, flush, record).
Names That Lie
A name lies when its words promise behaviour the code does not deliver. Detecting these costs nothing at authoring time and saves real debugging time later.
- Verb mismatch:
getThing() that calls a remote API, validate() that throws, parse() that returns null on failure (it should throw or be renamed tryParse).
- Boolean polarity inversion:
isInvalid set to true to mean valid; the codebase will eventually have if (!isInvalid) and someone will read it backwards. Use isValid and invert the value.
- Optional collapse:
getOrder() that returns Order | undefined. The caller has no way to know the function can return undefined without reading the implementation. Either rename to findOrder() (convention: "find" allows null return) or change to getOrderOrThrow().
- Stale meaning after refactor: a column originally named
created that, after a migration, now stores the ship date. The name predates the meaning. Rename the column AND all of its callers in the same commit.
- Domain-language drift: code says
User but the domain glossary says Account. Pick one in the glossary and rename in code.
Rename Coordination
Renaming is a small change that touches many places. Do all of them in one commit; ship none of them piecemeal.
- Pick the new name by the rules above.
- Find every call site:
grep -rn "OldName" --include="*.ts" --include="*.tsx" --include="*.md" (and equivalent for your language). Don't trust IDE rename — it misses dynamic references and string literals.
- Update all references in one diff. The diff stat should show the rename and nothing else. If you find yourself fixing other things along the way, split the commits.
- Decide on a deprecation alias when external consumers may have pinned to the old name. Export both names for one minor version; remove the old name in the next minor.
- Run the lint and test suite to catch dynamic references the grep missed (e.g., reflection, template strings, JSON config).
- Update docs in the same commit. Stale docs are a naming bug.
Verification
Do NOT Use When
| Use instead |
When |
refactor |
Restructuring already-named code (extract function, inline variable, split file) — naming may change as a side effect of the refactor |
documentation |
Writing prose explanation of a naming convention — this skill makes the choice; documentation explains it |
code-review |
Evaluating a whole PR — naming is one of many concerns the reviewer covers |
debugging |
Investigating why a misnamed identifier produces wrong behaviour — debugging chases the bug; naming-conventions prevents the next one |
1---2name: naming-conventions-23description: Use when naming a new file, function, variable, type, route, database column, environment variable, or any other code or system artifact. Covers identifier morphology (verb-noun choice, plural vs singular, prefix/suffix conventions), kebab-case vs camelCase vs snake_case vs PascalCase per artifact kind, abbreviation rules, name-vs-path semantics, the rename-coordination workflow, and detection of names that lie. Do NOT use for content writing (use `documentation`), for restructuring already-named code (use `refactor`), or for human-language copy in product UI (separate skill, not in this library).4license: MIT5---6## Concept of the skill78**What it is:** Naming conventions are the rules that make artifact names truthful, predictable, and searchable across code, routes, data, configuration, and documentation-adjacent developer surfaces.910**Mental model:** A name is a compact contract: artifact kind decides casing, grammar decides the role of each word, and verbs/nouns promise behavior. A good name lets the reader infer what the artifact does before opening the implementation.1112**Why it exists:** Names are read far more often than they are written. Choosing them deliberately prevents hidden cost: stale domain words, false verb promises, casing inconsistency, and missed references during renames.1314**What it is NOT:** It is not whole-code refactoring, whole-diff code review, prose style guidance, product microcopy, or debugging a failed behavior after the name has already misled someone.1516**Adjacent concepts:** Semantics, linguistics, refactor, code-review, debugging, version-control, and information architecture.1718**One-line analogy:** Naming is like labeling circuit breakers: a short label is useful only when it truthfully names the circuit it controls.1920**Common misconception:** Naming is not cosmetic. A misleading identifier creates a wrong model in every caller and reader, even when the code compiles.2122# Naming Conventions2324## Coverage2526- Identifier morphology: verb-noun selection (`get` vs `fetch` vs `load`), plural vs singular for collections, prefix/suffix conventions (`is` / `has` / `should` for booleans, `use` for React hooks)27- Casing per artifact kind: kebab-case (file names, URL paths, CLI flags), camelCase (JavaScript/TypeScript variables and functions), PascalCase (types, classes, components, React JSX), snake_case (Python, SQL columns, environment variables when convention demands), SCREAMING_SNAKE_CASE (constants, env-var keys)28- Abbreviation rules: when an abbreviation is universally known (`url`, `id`, `api`), when it requires expansion (`cust` → `customer`), and when team-internal jargon must be avoided in public-facing names29- Name-vs-path semantics: the difference between *what an artifact is called* and *where it lives*; when name and path agree (file system) vs when they diverge (TypeScript module re-exports, npm-published package paths)30- Rename coordination: how to update every reference in the same commit, when to ship a deprecation alias, and how to detect missed call sites with grep31- Names that lie: identifiers whose words promise a behaviour the code does not deliver, and how to detect them (the function called `getX` that also writes; the boolean called `isReady` that means "should be ready"; the column called `created` that stores the ship date)32- Cross-cutting consistency: when a naming choice in one part of the codebase forces a related choice elsewhere (table column `customer_id` and TypeScript type `Customer.id`)3334## Philosophy of the skill3536Names are the most-read part of any codebase. Every reader pays the cost of a bad name; only the author pays the cost of choosing well. The single most valuable property of a name is *truthfulness*: a name that lies — about what an artifact does, returns, or means — is more harmful than a name that is merely unclear. The second-most-valuable property is *consistency with sibling names*: a function called `getOrders` should sit alongside `getCustomers`, not `loadCustomers`. The third is *brevity*, and only the third — short names that mislead are not a virtue.3738When a name does not fit, the answer is almost always to rename, not to add a comment explaining what the name "really" means. Comments rot; renames travel with the code.3940## Casing per Artifact Kind4142Casing is project-convention-driven for the artifacts where languages don't enforce it, and language-mandated for the rest. Pick the convention once, document it in the project's CONTRIBUTING or AGENTS file, and apply it everywhere.4344| Artifact | Convention | Example |45|---|---|---|46| File name (any) | kebab-case | `order-pricing.ts`, `webhook-handler.py` |47| URL path segment | kebab-case | `/api/order-pricing` |48| CLI flag | kebab-case | `--include-template` |49| JS/TS variable, function, parameter | camelCase | `orderTotal`, `calculateMargin()` |50| JS/TS type, class, interface, React component | PascalCase | `Order`, `OrderPricing`, `<OrderRow/>` |51| Python variable, function | snake_case | `order_total`, `calculate_margin` |52| Python class | PascalCase | `Order`, `OrderPricing` |53| SQL table name | snake_case (lowercase) | `orders`, `order_line_items` |54| SQL column name | snake_case | `created_at`, `customer_id` |55| Environment variable | SCREAMING_SNAKE_CASE | `STRIPE_SECRET_KEY`, `NODE_ENV` |56| Constant in code | SCREAMING_SNAKE_CASE | `MAX_RETRIES`, `DEFAULT_TIMEOUT_MS` |57| Boolean variable / function | `is*` / `has*` / `should*` / `can*` prefix | `isAdmin`, `hasReceipt`, `shouldRetry` |58| React hook | `use*` prefix (mandatory) | `useOrders`, `useDebounce` |59| Predicate function | verb in interrogative form | `validateEmail()`, `isValidEmail()` |6061## Identifier Morphology6263The verb you pick encodes a contract. Choose deliberately.6465| Verb | Implies | Wrong when |66|---|---|---|67| `get` | Pure read; cheap; never mutates; idempotent | The function writes, calls an API, or has any side effect |68| `fetch` | Network or I/O read; may fail; may be slow | The function reads from local memory or never crosses a boundary |69| `load` | Read-and-cache, or read-from-disk; one-shot | The function returns synchronously from already-loaded data |70| `compute` / `calculate` | Pure transformation of inputs | The function takes no inputs or returns I/O |71| `validate` | Returns boolean OR throws; no side effects | The function modifies the input or has hidden side effects |72| `assert` | Throws on failure; void return on success | The function returns a value or has a happy non-throwing path |73| `parse` | String → structured data; may throw on malformed input | The function takes structured data or never throws |74| `format` | Structured data → string | The function returns structured data |75| `create` | Allocates/persists a new entity; returns its identity | The function returns a transient value with no persisted identity |76| `update` | Modifies an existing entity by identity | The function inserts or replaces |77| `delete` / `remove` | Removes an entity from the system | The function only removes from a transient view |7879The single most common naming bug is `getX` that also writes. If the function has a side effect, the verb must be one that *implies* side effects (`save`, `apply`, `commit`, `flush`, `record`).8081## Names That Lie8283A name lies when its words promise behaviour the code does not deliver. Detecting these costs nothing at authoring time and saves real debugging time later.8485- **Verb mismatch**: `getThing()` that calls a remote API, `validate()` that throws, `parse()` that returns null on failure (it should throw or be renamed `tryParse`).86- **Boolean polarity inversion**: `isInvalid` set to `true` to mean valid; the codebase will eventually have `if (!isInvalid)` and someone will read it backwards. Use `isValid` and invert the value.87- **Optional collapse**: `getOrder()` that returns `Order | undefined`. The caller has no way to know the function can return undefined without reading the implementation. Either rename to `findOrder()` (convention: "find" allows null return) or change to `getOrderOrThrow()`.88- **Stale meaning after refactor**: a column originally named `created` that, after a migration, now stores the ship date. The name predates the meaning. Rename the column AND all of its callers in the same commit.89- **Domain-language drift**: code says `User` but the domain glossary says `Account`. Pick one in the glossary and rename in code.9091## Rename Coordination9293Renaming is a small change that touches many places. Do all of them in one commit; ship none of them piecemeal.94951. **Pick the new name** by the rules above.962. **Find every call site**: `grep -rn "OldName" --include="*.ts" --include="*.tsx" --include="*.md"` (and equivalent for your language). Don't trust IDE rename — it misses dynamic references and string literals.973. **Update all references** in one diff. The diff stat should show the rename and nothing else. If you find yourself fixing other things along the way, split the commits.984. **Decide on a deprecation alias** when external consumers may have pinned to the old name. Export both names for one minor version; remove the old name in the next minor.995. **Run the lint and test suite** to catch dynamic references the grep missed (e.g., reflection, template strings, JSON config).1006. **Update docs** in the same commit. Stale docs are a naming bug.101102## Verification103104- [ ] The name is *truthful* — every word in the name describes behaviour the code actually delivers105- [ ] The casing matches the artifact-kind convention (file kebab, type PascalCase, env SCREAMING_SNAKE)106- [ ] The verb implies the right cost class (`get` is cheap, `fetch` may fail, `compute` is pure)107- [ ] Boolean prefix is positive polarity (`isValid` not `isInvalid`)108- [ ] Sibling artifacts use the same verb stem (don't mix `getOrders` with `loadCustomers`)109- [ ] No team-internal jargon in public-facing names (file names, route paths, error messages)110- [ ] Rename diffs touch ALL references in one commit, including docs and tests111112## Do NOT Use When113114| Use instead | When |115|---|---|116| `refactor` | Restructuring already-named code (extract function, inline variable, split file) — naming may change as a side effect of the refactor |117| `documentation` | Writing prose explanation of a naming convention — this skill makes the choice; documentation explains it |118| `code-review` | Evaluating a whole PR — naming is one of many concerns the reviewer covers |119| `debugging` | Investigating why a misnamed identifier produces wrong behaviour — debugging chases the bug; naming-conventions prevents the next one |