A Field Guide to Case Conversion: camelCase, snake_case, kebab-case
Jun 30, 2026 · 4 min read
camelCase shows up wherever JavaScript conventions rule: JSON API responses, JS/TS variable and function names, most frontend config files. snake_case shows up wherever Python or SQL conventions rule: database columns, Python variables and function names, a lot of REST API bodies written by backend teams that lead with Python, Ruby or Rails.
kebab-case is mostly a URL and CSS convention — file names, route segments, CSS class names, HTML attributes, npm package names — because hyphens are safe in places underscores and camelCasing sometimes aren't; a browser URL bar, a CLI flag, and an HTML `data-` attribute all treat hyphens as ordinary characters, where an underscore can be visually confused with a space and camelCase just looks wrong. PascalCase is reserved for types, classes and components across nearly every language, and SCREAMING_SNAKE_CASE is the near-universal convention for constants and environment variables specifically — `DATABASE_URL`, not `databaseUrl`, is what almost every `.env` file expects, precisely so a constant is visually distinct from a regular variable at a glance.
Acronyms are where every automatic converter, and most humans, disagree with each other. Is a user ID field `userID`, `userId`, or `user_id`? Converting `user_id` to camelCase mechanically gives `userId`, but a codebase with a strong Java or C# influence might expect `userID` with the acronym fully capitalized. There's no universally correct answer — the only real rule is picking one convention for acronyms and applying it consistently, because a codebase with both `userId` and `apiURL` reads as two people who never agreed on a style guide, which is usually exactly what happened.
HTTP headers have their own quirky history: they're conventionally written in Train-Case — `Content-Type`, `X-Request-Id` — a capitalized-word, hyphen-separated style that's really just PascalCase with hyphens instead of nothing between words. Header names are actually case-insensitive per the HTTP spec, so `content-type` and `Content-Type` are the same header to a compliant server, but the capitalized convention persists because it's what most tooling and documentation still renders.
GraphQL schemas lean camelCase for fields by convention, even when the backing database is snake_case, which means a GraphQL layer over a Postgres database is almost always doing a case conversion at the resolver level whether anyone wrote it explicitly or a library does it automatically. This is the same conversion problem showing up one layer higher in the stack, just with a framework quietly doing it instead of a developer.
dot.case shows up in a narrower set of places but is worth recognizing on sight: i18n translation keys (`errors.form.required`), nested config paths, and some logging and metrics libraries that use dots to represent hierarchy the way JSON uses nested objects. It's effectively snake_case's cousin for anything that's conceptually a path rather than a single identifier, and converting a deeply nested JSON structure into flat dot-notation keys (and back) is its own small, easy-to-get-wrong conversion — an array index in the path, an escaped literal dot inside a key name, that kind of thing.
Query parameters in a URL have looser conventions than almost anything else in this list, which is itself worth knowing: some APIs use snake_case (`?user_id=123`), some use camelCase (`?userId=123`), and some use kebab-case, entirely depending on the framework or team that built the API rather than any spec requirement. Unlike headers, there's no HTTP-level convention pushing query parameters toward one style, so the only reliable approach is checking each API's actual documentation rather than assuming it matches whatever convention the rest of that company's stack uses elsewhere.
Renaming a field across a codebase's naming convention — say, migrating a set of database columns from snake_case to a system that expects camelCase, or the reverse — is one of the more error-prone mechanical tasks in a migration, because it has to happen consistently across migration scripts, ORM models, API serializers and any hand-written SQL that references the old names, all at once. Generating the full set of renamed identifiers up front, in whichever case convention each layer needs, and diffing that list against what actually shipped is a cheap way to catch the one column that got missed before it becomes a runtime `undefined`.
The friction shows up hardest at the boundary between two systems that pick differently — a Python backend returning snake_case fields into a JavaScript frontend that wants camelCase, a database column name that needs to become a URL slug, or a constant that needs to move from an env var (`SCREAMING_SNAKE_CASE`) into application code (`camelCase` or `PascalCase`) without anyone mistyping it along the way. Doing that conversion by hand is exactly where typos creep in — a single letter transposed while manually retyping a 20-character identifier is a bug that won't show up until runtime.
That's the exact conversion the Text tool here handles — camelCase, PascalCase, snake_case, CONSTANT_CASE and kebab-case, all generated simultaneously so nothing gets mistyped along the way — along with Base64 and URL encoding for the adjacent problem of getting a string safely into a header or query string once the casing itself is no longer the issue.
More from the blog
5 Habits for Debugging Messy JSON Payloads Faster
The difference between a two-minute payload review and a twenty-minute one usually comes down to a few small habits.
SQL Formatting Conventions That Make Code Review Easier
A query that's easy to review is one where the diff shows the actual change, not a reflow of every line around it.
Testing Webhooks Locally Without Exposing Your Machine
You don't need to punch a hole in your firewall to see what a provider actually sends before your endpoint touches it.