If you've worked across more than one language for any length of time, you've felt the friction of identifier conventions. JavaScript wants camelCase. Python wants snake_case. CSS wants kebab-case. Constants want CONSTANT_CASE. Class names — almost universally — want PascalCase. Get it wrong and your code looks foreign to the next person who reads it; get it right and the convention does some of the work of explaining what each name is for.
This article walks through where each convention came from, where it actually belongs in 2026, and what to do at the boundaries between systems.
The four conventions you actually use
There are dozens of historical naming conventions, but the modern web sticks to four:
camelCase— first word lowercase, subsequent words capitalised. Variables, parameters, function names:getUserName,userId,parsedAt.PascalCase— every word capitalised. Class names, type names, React/Vue component names:UserAccount,OrderStatus,LoginForm.snake_case— lowercase words joined by underscores. Variables and functions in Python and Ruby; column and table names in SQL:user_name,created_at,order_items.kebab-case— lowercase words joined by hyphens. CSS class names, URL slugs, HTML attributes:primary-button,/blog/getting-started,data-user-id.
A fifth, CONSTANT_CASE (sometimes called SCREAMING_SNAKE_CASE), is reserved for compile-time constants and environment variables: MAX_RETRIES, DATABASE_URL. It signals "this value never changes at runtime" and isn't really a convention you choose — it's a convention that picks you when the situation demands it.
Pick by ecosystem, not by preference
The single biggest mistake new developers make is treating naming as a personal preference. It isn't — at least not at the variable and function level. Each ecosystem has a settled convention, and linters and code reviewers will quietly enforce it. Here's the short version of who uses what:
| Language | Variables / functions | Classes / types | Constants |
|---|---|---|---|
| JavaScript / TypeScript | camelCase |
PascalCase |
CONSTANT_CASE |
| Python (PEP 8) | snake_case |
PascalCase |
CONSTANT_CASE |
| Ruby | snake_case |
PascalCase |
CONSTANT_CASE |
| Rust | snake_case |
PascalCase |
CONSTANT_CASE |
| Go | camelCase (private), PascalCase (exported) |
PascalCase |
CONSTANT_CASE or PascalCase |
| C# | camelCase (parameters, locals), PascalCase (methods, properties) |
PascalCase |
PascalCase |
| PHP (PSR) | camelCase |
PascalCase |
CONSTANT_CASE |
| Java | camelCase |
PascalCase |
CONSTANT_CASE |
| Swift / Kotlin | camelCase |
PascalCase |
camelCase (Swift), CONSTANT_CASE (Kotlin) |
Across that whole table, classes and types are PascalCase everywhere. The split is on functions and variables — Python and Ruby's lineage prefers snake_case; the C / Java / JavaScript family prefers camelCase. Rust came later and chose snake_case deliberately because most code in a Rust file is functions and variables, and underscores read more like English prose.
Where casing crosses systems: APIs and databases
The interesting cases are at the boundaries — where one system's convention meets another's. Two come up constantly.
JSON over HTTP. What case do API keys take? In 2026, the dominant convention for new public APIs is camelCase: {"firstName": "Jane", "createdAt": "2026-05-07"}. Stripe, GitHub, OpenAI, and most newer APIs ship camelCase. The exceptions are large frameworks with strong server-side conventions: Rails APIs and Django REST Framework typically emit snake_case ({"first_name": "Jane"}), and most consumers happily handle either.
If you're designing a new API, pick one and stick with it everywhere. Don't mix. A response with {"firstName": "Jane", "user_id": 7} is the kind of inconsistency that haunts a codebase for years because every consumer has to special-case both styles.
Database columns. SQL is case-insensitive by default (in most engines) but column identifiers conventionally use snake_case: first_name, user_id, created_at. This is independent of the language you're calling SQL from — even a JavaScript codebase with camelCase everywhere maps columns to snake_case names. ORMs handle the translation automatically: in Eloquent, Active Record, and Django ORM, you write user.firstName (or user.first_name) and the ORM emits SELECT first_name FROM users underneath.
When the ORM doesn't handle it for you, do the conversion at one specific layer — typically the ORM's serialisation hook — rather than scattering ad-hoc converters through your business logic.
URL slugs are kebab-case, full stop
There's no debate here, but it's worth stating: URL slugs are kebab-case. Always.
✅ /blog/camelcase-vs-snake-case
❌ /blog/camelCaseVsSnakeCase
❌ /blog/camelcase_vs_snake_case
Two reasons. First, hyphens in URLs are treated as word separators by every search engine, while underscores aren't — Google's indexer reads camelcase-vs-snake-case as four words but camelcase_vs_snake_case as one. Second, hyphens are case-preserving in URLs but case-sensitivity in URLs is unreliable across servers, so any case-mixing convention introduces a duplicate-content risk. Lowercase kebab-case sidesteps both.
The same logic applies to file names served on the web — favour user-profile.tsx over userProfile.tsx for files that map to URL paths.
CSS is kebab-case too
CSS class names, custom properties, and custom HTML attributes all use kebab-case:
.primary-button { ... }
:root {
--color-text-primary: #1a1a1a;
}
<div data-user-id="42" data-loading-state="idle">
The hyphen isn't a syntactic accident — CSS uses spaces to separate selectors, so a multi-word class name has to use a non-space separator, and kebab-case is the standard one. Tailwind's class names follow this exactly: bg-gray-900, flex-col, hover:text-indigo-700.
A common gotcha: when you read a CSS custom property from JavaScript, you keep the kebab-case:
getComputedStyle(el).getPropertyValue('--color-text-primary')
But the style object on a DOM element exposes properties as camelCase:
el.style.backgroundColor = '#fff' // not background-color
This is the only place in the front-end stack where kebab-case and camelCase aren't interchangeable for the same concept.
Acronyms — the corner case
What do you do when a name contains an acronym? Is it getHTMLParser or getHtmlParser? parseURL or parseUrl?
The dominant convention in 2026 is treat acronyms as a single word: getHtmlParser, parseUrl, xmlSerialiser. This is the rule in Microsoft's .NET naming guidelines, Google's Java style guide, and most TypeScript projects.
The reason is consistency under transformation. If you ever need to convert getHTMLParser to snake_case, you have to decide whether HTML is one word or three:
- one word:
get_html_parser✅ readable - three words:
get_h_t_m_l_parser❌ unreadable
Treating acronyms as words means every transformation works the same way: getHtmlParser → get_html_parser → get-html-parser → GET_HTML_PARSER round-trips cleanly.
You'll still see legacy code with parseURL-style acronyms, especially in older Java and C# codebases. New code should follow the modern rule.
When you have to convert: use the right tool
Converting between conventions by hand is error-prone — easy enough for one identifier, painful for a whole file or a database schema. A few rules of thumb:
- Don't roll your own splitter. A correct word-boundary detector handles existing camelCase, hyphens, underscores, and acronym boundaries. Most regex one-liners get acronyms wrong.
- Convert at one layer. When you need to bridge JSON
camelCaseand databasesnake_case, do the conversion in your ORM's serialiser. Don't scatter conversions through controllers and views. - Don't convert at all if you don't have to. If your front-end already uses the same convention as your API, leave it alone. The principle of least surprise beats the principle of consistency-with-the-database.
For one-off conversions, the case converter on this site handles all eight conventions and the acronym corner case. Paste a name, click the target case, copy the result — that's it.
The summary
- Variables and functions: follow your ecosystem (
camelCasefor JS/Java/C#/Swift,snake_casefor Python/Ruby/Rust). - Classes and types:
PascalCaseeverywhere. - Constants and env vars:
CONSTANT_CASE. - CSS classes, HTML attributes, URL slugs, file names on the web:
kebab-case. - Database columns:
snake_case, regardless of host language. - JSON keys: pick one (
camelCaseorsnake_case) and stick with it across your whole API. - Treat acronyms as a single word:
parseHtmlTag, notparseHTMLTag.
Most of the cognitive load of multi-language work disappears once these defaults are internalised. The conventions exist for a reason — they encode "this is a class", "this is a constant", "this is a CSS class" without you having to say so. Lean on them.