camelCase vs snake_case: The Great Naming Debate

May 28, 20265 min read

Two Styles, One Problem

Every developer eventually faces this question: should you write firstName or first_name? The answer depends on your language, your team, and — surprisingly — on cognitive science. Let's break down the real differences.

Origins of Each Style

camelCase emerged from early programming languages where spaces were invalid in identifiers. Lisp hackers in the 1960s used hyphens (first-name), but when languages like C and Java reserved the hyphen for subtraction, developers shifted to capitalizing internal words. Smalltalk popularized the style, and Java cemented it as the default for millions of developers.

snake_case has older roots in C and the Unix tradition. Underscores were valid identifier characters and visually separated words without changing letter case. Python adopted snake_case wholesale in the 1990s, and Ruby followed. The style aligns naturally with how people write in plain English when spaces are not available (e.g., first_name).

What Research Says About Readability

In 2010, a controlled eye-tracking study by Binkley et al. found that snake_case identifiers were read 20% faster than camelCase identifiers on average. The underscores act as visual word boundaries, making it easier for the brain to split the identifier into its component words.

However, the study also found that familiarity reduces the gap. Developers who work primarily in camelCase languages perform almost as well with camelCase as with snake_case. The readability advantage shrinks with daily exposure.

A later replication by Schankin et al. (2017) confirmed the direction but found a smaller effect size (around 10%). The consensus: snake_case has a measurable edge for new readers, but the difference is small for experienced practitioners in either style.

Language Ecosystem Choices

The programming languages you use heavily influence which style feels natural. Here is how the major ecosystems line up.

EcosystemPrimary StyleReason
JavaScript / TypeScriptcamelCaseLanguage spec, DOM APIs, JSON
Java / KotlincamelCaseOfficial style guides
C#camelCase / PascalCaseMicrosoft conventions
Pythonsnake_casePEP 8 style guide
Rubysnake_caseCommunity convention
Rustsnake_caseCompiler-enforced for functions
GocamelCaseExport visibility tied to case
C / C++MixedNo single convention dominates

The JSON-to-Python Problem

One of the most practical pain points is the mismatch between JSON APIs (camelCase) and Python backends (snake_case). Every Python developer who consumes a JSON API has faced this:

{
  "firstName": "Alice",
  "lastName": "Smith",
  "isActive": true
}
# Manual conversion — tedious and error-prone
first_name = data["firstName"]
last_name = data["lastName"]
is_active = data["isActive"]

Popular solutions include:

  • pydanticalias_generator config option that maps camelCase to snake_case automatically
  • marshmallowdata_key parameter for field-level mapping
  • Custom deserialization functions — Convert keys at the API boundary

The key principle: convert at the boundary, use native conventions inside. Never let camelCase variables leak deep into a snake_case codebase.

Database Column Naming

Most SQL databases default to lowercase identifiers, and underscores handle word separation naturally. This makes snake_case the overwhelming convention for database schemas:

CREATE TABLE users (
    first_name VARCHAR(100),
    last_name VARCHAR(100),
    created_at TIMESTAMP
);

Object-relational mappers (ORMs) like SQLAlchemy, Django ORM, and ActiveRecord all default to snake_case column names. If your application uses camelCase internally, the ORM typically handles translation at the data layer boundary.

Handling Mixed Codebases

Large systems often combine languages. A typical web stack might involve JavaScript (camelCase) on the frontend, Python (snake_case) on the backend, and SQL (snake_case) in the database. Here is how to keep things manageable:

  1. Follow each language's convention inside its own layer. Do not write Python in camelCase to match the frontend.
  2. Convert at the boundaries. API serializers and ORM mappings handle the translation.
  3. Document the mapping convention. Make it clear where conversion happens so new developers do not duplicate or skip it.
  4. Use automated conversion tools. Libraries like humps (Python) or lodash.camelCase (JS) handle bulk conversions reliably.

Practical Comparison

AspectcamelCasesnake_case
Visual densityHigher (no separator characters)Lower (underscores add spacing)
Typing speedFaster (no underscore key)Slightly slower
Readability for new readersLowerHigher (research-backed)
Readability for experienced usersComparableComparable
Language supportJS, Java, C#, GoPython, Ruby, Rust, SQL
All-caps handlingAmbiguous (parseXML vs parseXml)Clear (parse_xml)

The all-caps ambiguity in camelCase is worth noting. How do you capitalized an acronym? parseXML? parseXml? parseXmL? Different teams answer differently. snake_case avoids the question entirely: parse_xml.

Key Takeaways

  • snake_case has a measurable readability edge for unfamiliar code, but familiarity closes the gap.
  • Your language ecosystem determines the "right" answer more than personal preference.
  • The JSON-to-Python mismatch is real — automate conversion at the API boundary.
  • Database schemas overwhelmingly use snake_case, regardless of application language.
  • In mixed-language stacks, follow each language's convention and convert at boundaries.
  • All-caps abbreviations are ambiguous in camelCase; snake_case sidesteps the issue entirely.

Try It Yourself

Need to switch between naming styles? Try this tool:

  • Case Converter — Instantly convert between camelCase, snake_case, PascalCase, and kebab-case