Every codebase is full of names — variables, functions, classes, database columns, API fields, CSS classes. The way you write those names is a naming convention, and it turns out that the choice between camelCase and snake_case (or any of the other popular styles) has real downstream consequences on readability, tooling, code review friction, and even runtime behavior at serialization boundaries.

This article gives you a clear mental model for each style, maps them to the languages and contexts where they belong, and explains what goes wrong when you mix them without a plan.

The Main Case Styles

There are five naming conventions you will encounter in nearly every professional codebase:

  • camelCase — the first word is lowercase, every subsequent word starts with a capital letter. No separators. Example: getUserProfile, maxRetryCount.
  • PascalCase (also called UpperCamelCase) — like camelCase but the very first letter is also capitalised. Example: UserProfile, HttpClient.
  • snake_case — all lowercase, words separated by underscores. Example: get_user_profile, max_retry_count.
  • kebab-case — all lowercase, words separated by hyphens. Example: get-user-profile, max-retry-count. Cannot be used as an identifier in most programming languages because - is the subtraction operator.
  • SCREAMING_SNAKE_CASE — all uppercase with underscores. Reserved for constants and environment variables. Example: MAX_RETRY_COUNT, DATABASE_URL.

None of these is inherently superior. What matters is that the choice aligns with the conventions of the language and ecosystem you are working in.

What Each Language Uses

Language communities have developed strong, well-documented conventions over decades. Using the wrong style in a given language makes your code feel foreign to other contributors — even when it compiles and runs correctly.

Language / ContextVariables & FunctionsClasses & TypesConstants
JavaScript / TypeScriptcamelCasePascalCaseSCREAMING_SNAKE_CASE
React / Svelte componentscamelCase (props)PascalCase (component name)SCREAMING_SNAKE_CASE
Pythonsnake_casePascalCaseSCREAMING_SNAKE_CASE
Rubysnake_casePascalCaseSCREAMING_SNAKE_CASE
GocamelCase (unexported)PascalCase (exported)PascalCase or camelCase
Rustsnake_casePascalCaseSCREAMING_SNAKE_CASE
CSS / HTML attributeskebab-caseN/AN/A
SQL columnssnake_caseN/AUPPER_SNAKE (keywords)
C# variables / fieldscamelCasePascalCase (classes, methods)PascalCase
JavacamelCasePascalCaseSCREAMING_SNAKE_CASE

Go is worth a special mention: its convention doubles as an access modifier. Any identifier that starts with an uppercase letter is exported (public); any identifier starting with a lowercase letter is unexported (package-private). The compiler enforces this, so naming convention and visibility are inseparable in Go.

Why Mixing Cases Causes Real Problems

Inconsistent naming is not just an aesthetic complaint. It creates concrete, measurable problems in day-to-day development:

  • Linters fail. ESLint's @typescript-eslint/naming-convention rule, Rust's built-in compiler warnings, and Python's Flake8 all flag identifiers that violate the expected style. A codebase with mixed conventions will produce a constant stream of lint noise, training developers to ignore warnings — including real ones.
  • Auto-import and IDE refactoring break down. When the same concept is spelled differently across files (userId vs user_id vs UserID), IDE "Find All References" and rename refactors miss some occurrences. This leads to runtime bugs that are hard to trace.
  • Code review friction. Reviewers spend cognitive energy on naming inconsistencies rather than logic and architecture. PR threads fill up with style comments that could have been caught by a formatter.
  • Onboarding cost. New team members have to infer the unwritten rules from the existing codebase, often getting them wrong and introducing more inconsistency.
  • API serialization mismatches. This is arguably the most dangerous category and deserves its own section.

The Serialization Boundary Problem

The most common case-style collision in web development happens at the boundary between a backend and a frontend — or between a database and an API. Backends written in Python, Ruby, or with a PostgreSQL database use snake_case. JavaScript frontends expect camelCase. Without an explicit transform layer, one of two bad things happens: the frontend uses snake_case identifiers everywhere (polluting the JS codebase), or the backend uses camelCase (polluting the Python/Ruby codebase).

Consider a user record returned from a Python/Django REST API and consumed in TypeScript:

// What the Python backend serializes:
{
  "first_name": "Ada",
  "last_name": "Lovelace",
  "created_at": "2026-04-04T12:00:00Z"
}

// What the TypeScript frontend ideally works with:
{
  firstName: "Ada",
  lastName: "Lovelace",
  createdAt: "2026-04-04T12:00:00Z"
}

The correct solution is a transform layer that converts keys at the boundary. Libraries like humps (JavaScript) do this automatically:

import humps from 'humps';

const response = await fetch('/api/users/1');
const raw = await response.json();
const user = humps.camelizeKeys(raw);
// user.firstName === "Ada" ✓

On the backend side, Django REST Framework's CamelCaseJSONParser and similar middleware handle the reverse transform. The key insight: each layer uses its own idiomatic convention, and the transform is an explicit, tested boundary — not an ad-hoc fix sprinkled through the codebase.

How to Enforce Naming Conventions

The best naming convention is one enforced automatically, so developers don't have to think about it during code review. Here are the tools by ecosystem:

  • JavaScript / TypeScript: ESLint with the @typescript-eslint/naming-convention rule. Configure it once in .eslintrc or eslint.config.js and it will flag violations on every file save.
  • Python: Flake8 with the pep8-naming plugin, or Ruff (faster, covers both linting and formatting). Both enforce PEP 8 naming out of the box.
  • Rust: The compiler itself warns on non-idiomatic names. rustfmt handles formatting. No additional configuration needed for basic enforcement.
  • Go: golint / staticcheck enforce naming and exported identifier comments. The compiler enforces the export visibility rule.
  • CSS: Stylelint with stylelint-selector-bem-pattern or a custom regex rule enforces kebab-case class names.
  • All languages: A written team style guide (even a short one) in the repo's README or CONTRIBUTING.md eliminates ambiguity for cases that automated tools miss (e.g., abbreviations like URL vs Url vs url).

Running these tools as part of your CI pipeline — not just as optional editor plugins — ensures that naming violations never make it into the main branch, regardless of editor setup or developer preference.

Quick Reference: When to Use Which

StyleUse forAvoid for
camelCaseJS/TS variables, functions, object keys; Go unexported identifiers; Java/C# variablesPython, Ruby, Rust functions; CSS class names; SQL columns
PascalCaseClasses, types, interfaces, components across almost every language; Go exported identifiersVariables, functions, CSS; anything that isn't a type or component
snake_casePython, Ruby, Rust variables/functions; SQL columns; database table namesJavaScript variables; CSS class names; Go identifiers
kebab-caseCSS class names; HTML attributes; URL slugs; npm package namesAny programming language identifier (invalid syntax in most languages)
SCREAMING_SNAKE_CASEConstants and environment variables in almost every languageVariables that change; functions; types

The pattern is consistent: follow what the language's own standard library does. Read the source of the standard library or framework you're building on top of. If NumPy uses snake_case, your data science code should too. If React uses PascalCase for components, so should yours.

When you need to convert between styles — renaming a batch of variables, transforming API keys, or exploring what a string looks like in different conventions — a dedicated tool saves time. The Word Case Swap utility on this site converts any text instantly between camelCase, PascalCase, snake_case, kebab-case, and SCREAMING_SNAKE_CASE, with no installation required.