camelCase vs snake_case (and the Rest)

Programming languages do not allow spaces inside identifiers, so every language community settled on its own way of gluing multiple words together. The result is a handful of “cases” you will see everywhere in code, URLs, config files, and databases. Here is the field guide.

The conventions

Style Example Where it is the standard
camelCase userProfile Variables and functions in JavaScript, Java, C#, Kotlin, Swift, Go (exported names use Pascal)
PascalCase (UpperCamelCase) UserProfile Class, type, interface, enum, and component names in most languages; React components
snake_case user_profile Variables and functions in Python, Ruby, Rust; SQL table and column names; many config keys
SCREAMING_SNAKE_CASE MAX_RETRIES Constants and environment variables, in essentially every language
kebab-case (dash-case) user-profile URLs and slugs, CSS class names and custom properties, HTML attributes, npm package names, CLI flags (--dry-run), Docker image names
Train-Case User-Profile HTTP header names (Content-Type), rare elsewhere
flatcase userprofile Go package names, some domain names; avoided otherwise because word boundaries vanish

SCREAMING_SNAKE_CASE and CONSTANT_CASE are two names for the same thing.

Why kebab-case cannot be used in code

A hyphen is the subtraction operator in almost every language, so user-profile would parse as “user minus profile.” That is why kebab-case survives only in contexts that are not executable code — URLs, CSS, config keys, filenames — where it reads cleanly, is easy to type, and is case-insensitive (helpful for URLs, which may be lowercased by servers).

Why converting between styles is not trivial

Changing case is not just lowercasing and swapping separators — you first have to find the word boundaries, and that is where naive converters fail:

  • XMLHttpRequest is three words: xml, http, request. A boundary occurs both before a capital that follows a lowercase (...pR...) and before the last capital of a run that precedes a lowercase (XMLHttp). A converter that only splits on “lowercase-then-uppercase” produces xmlhttp-request; one that only splits on every capital produces x-m-l-http-request. Neither is right.
  • Digits: is parseInt2 one token or parse int 2? Conventions differ.
  • Acronyms: some style guides write getHttpUrl, others getHTTPURL. There is no universal answer, so a round-trip conversion can legitimately lose the original casing of an acronym.

A good converter treats both “lowercase → uppercase” and “uppercase → uppercase-then-lowercase” as boundaries, and also splits on existing separators (spaces, hyphens, underscores).

The rule that actually matters

Match whatever the surrounding code, language, or project already uses. A file that mixes getUserName, get_user_email, and GetUserPhone is harder to read than any one of those styles applied consistently, because the reader’s eye loses its rhythm. When you join a codebase, adopt its conventions even if you prefer others.

Most ecosystems encode their conventions in a linter or formatter that can check or fix names automatically:

  • JavaScript/TypeScript: ESLint (camelcase rule), Prettier for layout.
  • Python: flake8/pylint/ruff enforce PEP 8 (snake_case for functions/variables, PascalCase for classes, UPPER for constants).
  • Ruby: RuboCop.
  • Go: gofmt and go vet (mixedCaps, never underscores).

Converting a name step by step

To turn any identifier into any style, do it in two stages: split into words, then re-join.

Take getHTTPResponseCode2:

  1. Split. Break before an uppercase that follows a lowercase (get|HTTP...), and before the last uppercase of a run that precedes a lowercase (HTTP|Response), and around digits by your chosen rule. Result: ["get", "HTTP", "Response", "Code", "2"].
  2. Normalise case of each word (usually lowercase): ["get", "http", "response", "code", "2"].
  3. Re-join for the target style:
    • camelCase: first word lowercase, rest Capitalised, no separator → getHttpResponseCode2
    • PascalCase: every word Capitalised → GetHttpResponseCode2
    • snake_case: lowercase, _ between → get_http_response_code_2
    • kebab-case: lowercase, - between → get-http-response-code-2
    • CONSTANT_CASE: uppercase, _ between → GET_HTTP_RESPONSE_CODE_2

Notice that the original had HTTP in all caps; a round trip through snake_case and back gives getHttpResponseCode2, not getHTTPResponseCode2. That acronym-casing loss is unavoidable without a dictionary of known acronyms, and it is why automated renames of acronym-heavy code need a human review.

Files and folders follow the same split

  • kebab-case for public-facing things: URL slugs, npm packages, most web project files (user-profile.tsx), CSS files, Docker images.
  • snake_case for Python modules and many data files (user_profile.py, raw_events.csv).
  • PascalCase for files that export a single class or React component in ecosystems that expect it (UserProfile.tsx, UserService.java).
  • Avoid spaces and mixed case in filenames that will be referenced from code or URLs — case-sensitivity differs between macOS, Linux, and Windows and causes builds that pass locally and fail in CI.

Quick reference: what to use where

  • A local variable or function → the language’s default (camelCase in JS, snake_case in Python/Ruby/Rust).
  • A class / type / React component → PascalCase.
  • A constant or env var → SCREAMING_SNAKE_CASE.
  • A URL slug, CSS class, file name, CLI flag → kebab-case.
  • A database table or column → snake_case (portable across SQL engines and avoids quoting).
  • A JSON key in an API → whatever the API’s existing style is; camelCase and snake_case are both common, just be consistent across the whole payload.

The bottom line

There are about six cases in common use, each with a home turf: camelCase and PascalCase in most application code, snake_case in Python/Ruby/SQL, kebab-case in URLs and CSS, SCREAMING_SNAKE_CASE for constants. Converting between them requires real word-boundary detection, especially around acronyms. The choice matters far less than applying one consistently — let a linter enforce it. See a string in every style at once, with correct boundary handling, in the case converter.