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:
XMLHttpRequestis three words:xml,http,request. A boundary occurs both before a capital that follows a lowercase (...p→R...) and before the last capital of a run that precedes a lowercase (XML→Http). A converter that only splits on “lowercase-then-uppercase” producesxmlhttp-request; one that only splits on every capital producesx-m-l-http-request. Neither is right.- Digits: is
parseInt2one token orparse int 2? Conventions differ. - Acronyms: some style guides write
getHttpUrl, othersgetHTTPURL. 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 (
camelcaserule), Prettier for layout. - Python:
flake8/pylint/ruffenforce PEP 8 (snake_case for functions/variables, PascalCase for classes, UPPER for constants). - Ruby: RuboCop.
- Go:
gofmtandgo 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:
- 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"]. - Normalise case of each word (usually lowercase):
["get", "http", "response", "code", "2"]. - 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
- camelCase: first word lowercase, rest Capitalised, no separator →
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.