camelCase vs snake_case vs kebab-case
Updated 19 August 2026 · 8 min read
Every codebase settles on a way of joining words in a name, and the choice is almost never about taste — it is about matching the language, the platform, or the tool that will read the identifier. This guide covers the four conventions you will actually meet, where each one belongs, and the acronym problem that breaks naive conversion between them.
The four conventions
camelCase starts lowercase and capitalises each subsequent word. PascalCase is identical except the first letter is also capitalised — it is sometimes called upper camel case. snake_case joins lowercase words with underscores. kebab-case uses hyphens, which is why it cannot be used for identifiers in most languages: the parser reads the hyphen as a minus sign. CONSTANT_CASE is snake_case in capitals, reserved by convention for values that never change.
What each language expects
These are conventions enforced by style guides and linters rather than by compilers, but ignoring them makes code look immediately foreign to anyone who works in that ecosystem.
| Language | Variables & functions | Types & classes | Constants |
|---|---|---|---|
| JavaScript / TypeScript | camelCase | PascalCase | CONSTANT_CASE |
| Python | snake_case | PascalCase | CONSTANT_CASE |
| Ruby | snake_case | PascalCase | CONSTANT_CASE |
| Rust | snake_case | PascalCase | CONSTANT_CASE |
| Go | camelCase / PascalCase | PascalCase | PascalCase |
| Java | camelCase | PascalCase | CONSTANT_CASE |
| C# | PascalCase (public) | PascalCase | PascalCase |
| PHP | camelCase | PascalCase | CONSTANT_CASE |
| SQL | snake_case | snake_case | — |
| CSS | kebab-case | — | --kebab-case |
userName to UserName in Go is not a style change, it is an API change.Outside code: where kebab-case wins
Hyphens are illegal in identifiers but ideal almost everywhere else, because they are the one separator that both humans and search engines read as a word boundary.
| Context | Convention | Why |
|---|---|---|
| URLs and slugs | kebab-case | Google treats a hyphen as a separator and an underscore as a joiner |
| CSS classes | kebab-case | Matches CSS property naming, and hyphens are valid in selectors |
| HTML attributes | kebab-case | Required for data-* attributes |
| Environment variables | CONSTANT_CASE | Shells only reliably support letters, digits and underscores |
| Database tables and columns | snake_case | Most SQL engines fold unquoted identifiers to lower case |
| JSON API fields | camelCase or snake_case | Follow whatever the consuming client uses; consistency matters more than the choice |
| File names | kebab-case | Case-insensitive filesystems make mixed case unreliable |
| Git branches | kebab-case | Readable in URLs and safe across filesystems |
The underscore-versus-hyphen point for URLs is worth stating precisely, because it is the one with a measurable consequence. Google has confirmed it splits free-online-tools into three words while reading free_online_tools as a single token. For anything that appears in a URL, use hyphens.
The acronym problem
Converting between conventions means splitting a name into words first, and that split is where most implementations quietly fail. Boundaries occur at underscores, hyphens, spaces, and at any lowercase-to-uppercase transition. That last rule is what breaks on acronyms.
Handling this properly requires a lookahead rule: a run of capitals is one word, except that its final capital belongs to the next word if a lowercase letter follows. Because that is easy to get wrong, several major style guides now recommend avoiding the situation entirely — Google's Java guide and much of the Go ecosystem prefer parseHttpResponse, treating an acronym as an ordinary word. If you are starting a new codebase, that convention will save you a category of bug.
Converting at API boundaries
A common friction point is a Python or Rails backend using snake_case talking to a JavaScript frontend using camelCase. There are three workable answers, and the wrong one is to convert ad hoc in whichever file happens to need it.
Either pick one convention for the wire format and have both sides accept it, which is simplest and what most public APIs do; or convert in exactly one place, a serialisation layer that transforms every payload on the way in and out; or generate typed clients from a schema so the mapping is produced automatically. All three work. Scattering manual conversions through business logic does not, because the one field somebody forgets becomes a bug that only appears for a specific record.
Frequently asked questions
What is the difference between camelCase and PascalCase?
Only the first letter. camelCase begins lowercase, PascalCase begins uppercase. Most languages use camelCase for variables and functions and PascalCase for classes and types.
Why can I not use kebab-case in code?
Because the parser reads the hyphen as a subtraction operator, so user-name is interpreted as user minus name. Lisp dialects are the notable exception. This is why code uses underscores and URLs use hyphens.
Should URLs use hyphens or underscores?
Hyphens. Google treats a hyphen as a word separator and an underscore as a word joiner, so hyphenated slugs are read as separate words while underscored ones are read as one.
Does the convention I pick actually matter?
Matching your language ecosystem matters, because it makes code readable to anyone who joins. Beyond that, internal consistency matters far more than which convention you chose. The only case where it changes behaviour is Go, where capitalisation controls export.