camelCase vs snake_case vs kebab-case: Naming Conventions by Language
Every language community settled on its own way of joining words into identifiers, and the style guides are explicit about it. Following them is not about taste: linters flag deviations, serializers depend on them, and a mismatch at a boundary, such as a JSON API in one style feeding a database in another, is a steady source of bugs. This is a reference to what each ecosystem expects, how acronyms are handled, and how to convert safely at the edges.
The short version
- camelCase for variables and functions in JavaScript, TypeScript, Java, Kotlin and Swift; snake_case in Python, Ruby and Rust.
- PascalCase for classes and types almost everywhere, and for all public members in C# and exported names in Go.
- CONSTANT_CASE for constants and environment variables; kebab-case for URLs, CSS classes, file names and CLI flags.
- Pick one acronym rule and apply it consistently: most modern style guides treat acronyms as words (
XmlParser,userId); Go keeps them in capitals (userID). - Convert at the boundary with your serializer's naming policy, not by hand in business logic.
The styles, named
| Style | Example | Also called |
|---|---|---|
| camelCase | customerOrderId | lower camel case, dromedary case |
| PascalCase | CustomerOrderId | upper camel case, StudlyCaps, CapWords |
| snake_case | customer_order_id | lower snake case |
| CONSTANT_CASE | CUSTOMER_ORDER_ID | SCREAMING_SNAKE_CASE, upper snake case |
| kebab-case | customer-order-id | dash case, lisp case, spinal case |
| Train-Case | Customer-Order-Id | HTTP header case |
| dot.case | customer.order.id | used for configuration keys and log fields |
Readability research is mixed: eye-tracking studies have found snake_case read slightly faster by some people and camelCase by others, mostly according to what they were used to. The practical argument is consistency. A codebase where every name follows the ecosystem's convention is easier to search, easier to review, and works with the tools that assume it.
By language
| Language | Variables & functions | Types & classes | Constants | Source |
|---|---|---|---|---|
| Python | snake_case | PascalCase | CONSTANT_CASE | PEP 8 |
| JavaScript / TypeScript | camelCase | PascalCase | CONSTANT_CASE or camelCase | Common practice, Google style guides |
| Java / Kotlin | camelCase | PascalCase | CONSTANT_CASE | Java conventions, Google Java Style |
| C# | camelCase locals and parameters; PascalCase methods and properties | PascalCase, interfaces prefixed I | PascalCase | .NET design guidelines |
| Go | camelCase unexported, PascalCase exported | same rule | same rule | Effective Go |
| Rust | snake_case | PascalCase | CONSTANT_CASE | Rust API guidelines (RFC 430) |
| Ruby | snake_case | PascalCase | CONSTANT_CASE | Ruby style guide |
| PHP | camelCase methods | PascalCase | CONSTANT_CASE | PSR-1 |
| Swift | camelCase | PascalCase | camelCase | Swift API design guidelines |
In Go the case is not just style: a name that starts with a capital letter is exported from its package, and one that starts with a lower-case letter is private, so renaming a function from parseConfig to ParseConfig changes its visibility. In C#, the .NET guidelines put public members in PascalCase, and the runtime's own code base uses _camelCase for private fields.
Outside the code: data, URLs and infrastructure
- SQL. Use
snake_casefor tables and columns. PostgreSQL folds unquoted identifiers to lower case, so a column created as"orderId"must be quoted in every query forever after, whileorder_idnever needs quotes. - JSON APIs. Both camelCase (Google's JSON style guide, most JavaScript-first APIs) and snake_case (GitHub, Stripe, Slack) are common. Choose one per API and never mix them within a payload.
- URLs. Use lowercase kebab-case slugs. Google's own guidance recommends hyphens rather than underscores to separate words in URLs, and lower case avoids duplicate addresses on case-sensitive servers.
- CSS. Class names and custom properties are conventionally kebab-case (
.card-header,--brand-text); the BEM methodology addsblock__element--modifier. - Environment variables.
CONSTANT_CASE, such asDATABASE_URL, by universal convention and because many shells do not accept hyphens in variable names. - HTTP headers. Written in Train-Case by convention (
Content-Type), but header names are case-insensitive, and HTTP/2 and HTTP/3 transmit them in lower case. Never compare header names case-sensitively. - Files and packages. Kebab-case for web assets and npm packages, which must be lower case; snake_case for Python modules, which cannot contain hyphens because the file name becomes the import name.
Acronyms and initialisms
The hardest case in camelCase and PascalCase is a name that contains an acronym. There are two schools. One keeps acronyms in capitals: XMLHttpRequest, userID, ServeHTTP. Go's code review guidelines require this, and some browser APIs follow it. The other treats an acronym as an ordinary word: XmlHttpRequest, userId, HtmlParser. Google's Java and JavaScript style guides, the Rust API guidelines and most modern codebases prefer this, because consecutive capitals make word boundaries ambiguous: is HTTPSURL "HTTPS URL" or "HTTP SURL"? The .NET guidelines split the difference, keeping two-letter acronyms in capitals (IOStream) and treating longer ones as words (XmlReader).
Whichever rule a project follows, conversion tools need to understand both. A good converter splits XMLHttpRequest into XML · Http · Request and getUserID2FA into get · User · ID · 2 · FA, so that the snake_case form is xml_http_request rather than x_m_l_http_request.
Converting at the boundary
When data crosses from one convention to another, convert once, at the edge, with the serializer's built-in naming policy. Hand-written mapping code drifts out of date the first time someone adds a field. Most ecosystems support it directly:
# Python, Pydantic v2: snake_case fields, camelCase JSON
class Order(BaseModel):
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
order_id: int
// Java, Jackson: camelCase fields, snake_case JSON
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
class Order { long orderId; }
// C#, System.Text.Json: PascalCase properties, camelCase JSON
new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
// Rust, serde
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Order { order_id: u64 }
For one-off jobs, such as renaming a column list, generating constants from a spreadsheet header or turning a page title into a URL slug, a converter that works line by line is faster. Our text case converter converts a pasted list of names into seventeen styles at once and handles acronyms and digits the way described above.
Related guides and tools
Frequently asked questions
Only the first letter. camelCase starts in lower case and capitalises each following word, as in orderTotal; PascalCase capitalises every word including the first, as in OrderTotal. Most languages use camelCase for variables and functions and PascalCase for classes and types. C# also uses PascalCase for methods and properties, and Go uses it to mark a name as exported.
Either is acceptable, as long as an API uses one style throughout. camelCase matches JavaScript clients and Google's JSON style guide; snake_case matches Python and Ruby backends and is used by APIs such as GitHub and Stripe. Pick the one that matches most of your consumers, document it, and let the serializer convert to your server's internal style.
PEP 8, Python's style guide, uses snake_case for functions, variables, methods and module names, PascalCase (which it calls CapWords) for classes and exceptions, and CONSTANT_CASE for module-level constants. A single leading underscore marks a name as internal, and a double leading underscore triggers name mangling inside classes.
Hyphens. Google's URL structure guidance recommends hyphens to separate words because search engines treat a hyphen as a word separator, while an underscore may join words together. Use lower case as well, since paths are case-sensitive on most servers and mixed case creates duplicate addresses for the same page.
Follow your language's style guide. Go keeps acronyms in capitals, as in userID and ServeHTTP. Google's Java and JavaScript guides and the Rust guidelines treat them as words, as in userId and XmlParser, which keeps word boundaries readable. .NET keeps two-letter acronyms capitalised and treats longer ones as words. Consistency within a codebase matters more than which rule you choose.