Every team has had this argument at least once. Someone opens a pull request with user_first_name, the reviewer's linter is configured for userFirstName, and now two people are debating tabs versus spaces all over again except it's capitalization this time. It feels petty right up until the day a config key doesn't match the environment variable that's supposed to map to it, and a deploy fails at 5pm on a Friday.
Naming conventions aren't cosmetic. They're a coordination protocol. Get them wrong and every new file is a small negotiation; get them right and nobody has to think about it again. The general concept has its own Wikipedia entry if you want the formal definition, but the practical version is simpler: pick a convention per context, write it down, and stop relitigating it.
Photo by Polina Zimmerman on Pexels
Why this keeps coming up
Most codebases end up with more than one convention in play at the same time, and not because anyone planned it that way. A JavaScript frontend talks to a Python backend. The frontend uses camelCase because that's the JavaScript convention. The backend uses snake_case because that's PEP 8. Somewhere in between, a JSON payload has to pick one, and now someone's writing a serializer just to translate between the two.
Add in URL slugs (which almost always want kebab-case for readability and SEO), environment variables (SCREAMING_SNAKE_CASE by near-universal convention), and class names (PascalCase in most C-family and object-oriented languages), and a single project can easily be running four or five conventions simultaneously, each correct in its own context and confusing everywhere else.
The problem isn't that any one of these is wrong. It's that nobody wrote down which one applies where, so every contributor has to guess or, worse, match whatever they see in the nearest file, which propagates whatever inconsistency was already there.
The conventions, briefly
- camelCase:
firstName,getUserById. Standard for variables and functions in JavaScript, Java, and Swift. Wikipedia's entry on the term has the naming history if you're curious where "camel" came from. - PascalCase (sometimes called UpperCamelCase):
UserAccount,HttpClient. Standard for classes and types across most typed and object-oriented languages. - snake_case:
first_name,get_user_by_id. The default in Python, per PEP 8, and common in Ruby, Rust, and most database column names. - kebab-case:
first-name,user-account. Not valid as an identifier in most programming languages (hyphens read as subtraction), but the standard for URL slugs and CSS class names. - CONSTANT_CASE:
MAX_RETRY_COUNT,API_BASE_URL. Reserved for constants and environment variables in nearly every language that has a convention for constants at all.
Photo by Pixabay on Pexels
None of these is objectively superior. They solve different problems: readability inside a language's parser, readability inside a URL, or visual distinction between a constant and a variable at a glance.
How to actually decide
1. Match the ecosystem, not your preference. If you're writing Python, use snake_case for functions and variables, even if you personally find camelCase more compact. Fighting the ecosystem's convention means every library you import looks inconsistent with your own code, forever. The same logic applies to Rust, Ruby, PHP, and Go, each of which has its own idiomatic default (gofmt in particular has opinions and will fight you).
2. Pick one boundary translation point, not many. If your frontend is camelCase and your backend is snake_case, that's fine, as long as the translation happens in exactly one place: a serializer, a DTO layer, an API gateway. The failure mode isn't having two conventions. It's having the same field translated inconsistently in three different files because nobody centralized it.
3. Write it down before the second contributor joins. A one-paragraph note in your README or CONTRIBUTING file, "we use snake_case for Python, camelCase for the JS frontend, kebab-case for URLs," resolves 90% of future naming debates before they start. Teams that skip this step end up litigating the same decision in every code review indefinitely.
4. Treat existing code as the tiebreaker. If a file, module, or repo already has an established convention, match it, even if it's not your favorite. A file that's 80% snake_case with three camelCase variables sprinkled in is worse than a file that's 100% consistently "wrong."
"The naming convention argument is really a proxy for a bigger question: does this team have any shared standards at all, or is every file a fresh decision? Once you answer that, the specific casing barely matters." - Dennis Traina, founder of 137Foundry
Where this actually bites teams
Two spots cause more real bugs than the aesthetic debate ever will.
Photo by Vanessa Garcia on Pexels
Database columns versus API fields. Postgres and MySQL columns are conventionally snake_case. A JSON API response is conventionally camelCase. If your ORM auto-maps column names to API fields without an explicit translation layer, you'll eventually ship a field named createdAt that silently doesn't map to created_at in the database, and debugging that mismatch costs more time than writing the mapping ever would have.
Environment variables versus config objects. DATABASE_URL (the environment variable) becoming config.databaseUrl (the JS config object) is a completely standard translation, but it has to happen somewhere explicit. Teams that skip this and just do process.env.DATABASE_URL scattered through the codebase end up with no single source of truth for what environment variables the app actually reads.
When you're converting text by hand, don't
Manually retyping a list of fields from snake_case to camelCase, or a page title into a URL-safe kebab-case slug, is exactly the kind of task that introduces typos that are hard to spot on review. A dropped underscore or a stray capital letter looks identical to the correct version at a glance and only surfaces when the build fails or the API call 404s.
This is a narrow, well-defined problem, which makes it a good one to hand to a small dedicated tool rather than a text editor's find-and-replace. EvvyTools' Case Converter converts between all of the conventions above (camelCase, PascalCase, snake_case, kebab-case, CONSTANT_CASE, dot.case, and a few more) in one pass, with word and character counts so you can confirm nothing got mangled in the conversion. For bulk conversions, like renaming a full list of database columns to their JS equivalents, the line-by-line batch mode handles the whole list at once instead of one field at a time.
Migrating an existing codebase
Sometimes the decision isn't "what convention should we use going forward" but "we picked wrong two years ago and now half the codebase disagrees with the other half." Migrating an established convention is riskier than picking one for a new project, because a rename touches every call site, every test, and often every row in a database.
A few things make this safer:
Rename in one pull request per module, not one giant sweep. A single PR that touches four hundred files across the whole repo is nearly impossible to review properly, and any mistake buried inside it is easy to miss. Renaming module by module keeps each change reviewable and lets you catch mistakes before they compound.
Keep a compatibility shim at API boundaries during the transition. If external clients depend on a snake_case response shape and you're moving the internal codebase to camelCase, add a translation layer at the API boundary rather than breaking every consumer at once. Remove the shim once every known consumer has migrated, not before.
Database columns are the expensive case. Renaming a column touches migrations, every query that references it by name, and potentially every ORM model. If the column name itself isn't causing active bugs, it's often not worth the migration risk just for consistency. Prioritize renames where the inconsistency is actually causing defects, not just aesthetic mismatches.
Automate what you can, but review the diff. Tools like codemod, language server rename-refactoring, or a scripted find-and-replace can handle the mechanical part of a rename across many files. They still need a human to review the resulting diff, because automated renames occasionally catch a string literal or a comment that shouldn't have changed.
Formalizing it for a team
Photo by www.kaboompics.com on Pexels
Once you've picked your conventions, the fastest way to make them stick is to enforce them automatically rather than relying on code review to catch violations:
- Linters like ESLint (with
camelcaserule) or Python'spylintwill flag naming violations automatically, turning a style guideline into a build failure instead of a review comment. - Style guides from major engineering orgs are a reasonable default if you don't want to write your own from scratch. Google's published style guides cover multiple languages and are a common starting point for teams that want a documented, external reference rather than an internal debate.
- Editor config files (
.editorconfig, language-specific formatter configs) catch whitespace and casing issues before they ever reach a pull request.
None of this requires perfect adherence on day one. It requires a decision, a place that decision lives, and a way to enforce it that doesn't depend on a human remembering to bring it up in every review.
The short version
Naming conventions aren't a matter of taste once a codebase has more than one contributor. camelCase, snake_case, PascalCase, kebab-case, and CONSTANT_CASE each have a context where they're the obvious right answer, and the actual skill is matching convention to context consistently rather than picking a personal favorite and forcing it everywhere. Write the decision down, centralize the translation points, and let a tool handle the mechanical conversion work so typos don't sneak into the process.
For more on formatting text efficiently, see the tools directory or browse the EvvyTools blog for other writing and content guides.