The Cases
| Case | Example | Where it belongs |
|---|---|---|
| camelCase | getUserName | JavaScript, Java, Swift variables and methods |
| PascalCase | GetUserName | Type names, C# methods, React components |
| snake_case | get_user_name | Python, Ruby, SQL columns |
| SCREAMING_SNAKE_CASE | GET_USER_NAME | Constants, environment variables |
| kebab-case | get-user-name | URLs, CSS classes, file names, HTML attributes |
| Train-Case | Get-User-Name | HTTP headers, PowerShell cmdlets |
| dot.case | get.user.name | Config keys, i18n message paths |
The Acronym Problem
Splitting camelCase looks trivial until an acronym appears:
``javascript
// Naive: break before every capital
'XMLHttpRequest'.replace(/([A-Z])/g, ' $1')
// " X M L Http Request" β wrong
// Correct: also break between a run of capitals and a following word
'XMLHttpRequest'
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
// "XML Http Request" β right
`
The second rule is what separates XMLHttp into XML + Http. Without it,
parseHTMLString becomes parse_h_t_m_l_string.
Consistency Beats Preference
Every mainstream style guide picks one convention per context and holds it. The cost of
mixed conventions is not aesthetic β it is that userId, user_id and userID all
appear in the same codebase and none of them can be found by searching for the others.
| Ecosystem | Variables | Types | Files |
|---|---|---|---|
| JavaScript / TypeScript | camelCase | PascalCase | kebab-case |
| Python | snake_case | PascalCase | snake_case |
| Go | camelCase / PascalCase for exported | PascalCase | lowercase |
| Rust | snake_case | PascalCase | snake_case |
Splitting Is the Hard Part
Converting between cases looks like a formatting problem and is really a tokenising one.
Before anything can be re-joined as camelCase or snake_case, the input has to be cut
into words β and the input arrives in any convention at all.
The rule that separates a working converter from a broken one is acronym handling. Two
substitutions are needed, not one:
`javascript
const words = (s) =>
s.replace(/([a-z0-9])([A-Z])/g, '$1 $2') // fooBar -> foo Bar
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2') // XMLHttp -> XML Http
.replace(/[^a-zA-Z0-9]+/g, ' ')
.trim()
.split(/\s+/);
`
Omit the second and parseHTMLString becomes parse_h_t_m_l_string. Every tool here
applies both, which is why XMLHttpRequest splits into XML, Http, Request.
The Conventions, Side by Side
| Case | Example | Where it is required |
|---|---|---|
| camelCase | totalOrderCount | JavaScript, Java, C# members |
| PascalCase | TotalOrderCount | Types, classes, React components, exported Go |
| snake_case | total_order_count | Python, Ruby, SQL, Rust |
| SCREAMING_SNAKE | TOTAL_ORDER_COUNT | Constants, environment variables |
| kebab-case | total-order-count | URLs, CSS classes, HTML attributes |
| Train-Case | Total-Order-Count | HTTP headers |
| dot.case | total.order.count | Config keys, i18n paths, packages |
Some of These Are Enforced, Not Suggested
It is worth knowing which conventions are style and which are semantics, because the second
kind produces bugs rather than review comments:
Go: capitalisation *is* access control.Nameis exported from the package;name
is not.
React: JSX compiles a lowercase tag to a string.renders nothing and
raises no error; works.
- Ruby: an identifier starting with a capital is a constant, so naming a method
MyMethod changes what it is.
- SQL: most engines fold unquoted identifiers to one case. A column created as
userId becomes userid and needs quoting forever after.
- Docker: repository names must be lowercase; the daemon rejects anything else outright.
- POSIX environment variables: letters, digits and underscore only, and not leading with
a digit. Shells silently ignore anything else.Pick by Destination, Not by Preference
The pages here are grouped two ways. Some are named after the convention β
[camelCase](/dev/camel-case-converter),
[snake_case](/dev/snake-case-converter),
[kebab-case](/dev/kebab-case-converter),
[PascalCase](/dev/pascal-case-converter),
[CONSTANT_CASE](/dev/case-converter/constant-case-converter),
[Title Case](/dev/title-case-converter). Others are named after the place the
output is going: a [CSS class](/dev/case-converter/css-class-name-converter), a
[SQL column](/dev/case-converter/sql-column-name-converter), a
[Docker image](/dev/case-converter/docker-image-name-converter), an
[environment variable](/dev/case-converter/env-variable-name-converter), a
[Terraform resource](/dev/case-converter/terraform-resource-name-converter).
The second group is usually the one you want, because it answers the question you actually
have β not "what is kebab-case" but "what should I call this thing".
Mixed Conventions Are a Search Problem
Inconsistent naming inside one codebase is not an aesthetic complaint. userId,
user_id and userID` are three different identifiers, and none of them finds the others
in a grep, a rename or a code review. Pick whatever the language's own standard library
uses and hold it β that is the convention every reader already expects.