Every developer has wasted time debating naming conventions. Should this variable be userId, user_id, or user-id? The answer depends entirely on where you're writing the code. Here's the definitive guide to which convention belongs where and why.
The major naming conventions
| Convention | Example | Also called |
| camelCase | userId, firstName | lower camelCase |
| PascalCase | UserId, FirstName | upper CamelCase |
| snake_case | user_id, first_name | underscore case |
| SCREAMING_SNAKE_CASE | MAX_RETRIES, API_KEY | constant case |
| kebab-case | user-id, first-name | dash case, hyphen case |
| SCREAMING-KEBAB-CASE | Content-Type, X-Request-Id | (HTTP headers) |
A brief history
These conventions didn't emerge randomly. They evolved from technical constraints and community preferences.
snake_case is the oldest of the three main conventions. It dates back to C programming in the 1970s, where it was the dominant style. The underscore was chosen because spaces aren't allowed in identifiers, and underscores are visually similar to spaces. The C standard library uses it throughout: str_len, mem_cpy (well, strlen, memcpy -- early C was stingy with underscores).
camelCase became popular with Smalltalk in the 1980s and later dominated through Java in the 1990s. The reasoning: no separator character needed, and the uppercase letters provide visual word boundaries. Java's standard library (getInputStream, toString) cemented this as the convention for an entire generation of developers.
kebab-case comes from Lisp (1958, actually the oldest origin) where hyphens are valid in identifiers: (define make-greeting ...). It later became the standard in HTML/CSS because hyphens are valid in CSS property names and HTML attributes, while underscores historically had inconsistent browser support in CSS.
Convention by language
JavaScript / TypeScript
// Variables and functions: camelCase
const userId = 42;
function getUserById(id) { ... }// Classes and components: PascalCase
class UserService { ... }
function UserProfile() { ... } // React component
// Constants: SCREAMING_SNAKE_CASE
const MAX_RETRY_COUNT = 3;
const API_BASE_URL = 'https://api.example.com';
// File names: kebab-case (common) or camelCase
// user-profile.js, user-profile.component.ts
// OR: userProfile.js
The JS ecosystem isn't fully consistent on file names. React projects often use PascalCase for component files (UserProfile.tsx), while Node.js and utility files tend toward kebab-case (database-utils.js).
Python
# Variables and functions: snake_case
user_id = 42
def get_user_by_id(user_id): ...Classes: PascalCase
class UserService: ...Constants: SCREAMING_SNAKE_CASE
MAX_RETRY_COUNT = 3Module/file names: snake_case
user_service.py, database_utils.py
Private: leading underscore
_internal_cache = {}
def _validate_input(data): ...
Python's PEP 8 style guide is one of the most widely followed in any language. Nearly all Python code uses snake_case for functions and variables. Using camelCase in Python is an immediate tell that the code was written by someone coming from Java or JavaScript.
CSS
/ Properties and custom classes: kebab-case /
.user-profile {
background-color: #fff;
font-size: 16px;
--primary-color: #3b82f6;
}/ BEM methodology /
.user-card__header--highlighted {
border-color: var(--primary-color);
}
CSS has no choice here -- property names are kebab-case by spec (background-color, not backgroundColor). Custom class names follow the same convention for consistency.
Go
// Exported (public): PascalCase
func GetUserByID(id int) User { ... }
type UserService struct { ... }// Unexported (private): camelCase
func validateInput(data string) bool { ... }
var maxRetries = 3
// Acronyms stay uppercase
type HTTPClient struct { ... } // not HttpClient
var userID int // not userId
Go is unique in that the naming convention determines visibility. PascalCase = exported (public), camelCase = unexported (private). This isn't just convention -- it's enforced by the compiler.
Ruby
# Variables and methods: snake_case
user_id = 42
def get_user_by_id(id) ... endClasses and modules: PascalCase
class UserService ... endConstants: SCREAMING_SNAKE_CASE (or PascalCase)
MAX_RETRY_COUNT = 3
Java / Kotlin
// Variables and methods: camelCase
int userId = 42;
public User getUserById(int id) { ... }// Classes: PascalCase
public class UserService { ... }
// Constants: SCREAMING_SNAKE_CASE
public static final int MAX_RETRY_COUNT = 3;
// Packages: all lowercase
package com.example.userservice;
Rust
// Variables and functions: snake_case
let user_id = 42;
fn get_user_by_id(id: u32) -> User { ... }// Types and traits: PascalCase
struct UserService { ... }
trait Authenticatable { ... }
// Constants: SCREAMING_SNAKE_CASE
const MAX_RETRY_COUNT: u32 = 3;
// Crate and module names: snake_case
// user_service, database_utils
Rust's compiler will actually warn you if you use the wrong convention. Using userId for a variable triggers a non_snake_case warning.
Convention by context
Database columns and tables
-- Tables: snake_case (plural by convention)
CREATE TABLE user_accounts (
user_id SERIAL PRIMARY KEY,
first_name VARCHAR(100),
created_at TIMESTAMP
);
SQL is case-insensitive for identifiers, but snake_case is the overwhelming standard. Some ORMs map between snake_case database columns and camelCase code properties automatically.
REST APIs
This is where it gets contentious. Both are common:
// snake_case (GitHub, Stripe, Twilio)
{
"user_id": 42,
"first_name": "Alice",
"created_at": "2026-01-15T10:30:00Z"
}// camelCase (Google, Facebook)
{
"userId": 42,
"firstName": "Alice",
"createdAt": "2026-01-15T10:30:00Z"
}
Pick one and be consistent. If your API is primarily consumed by JavaScript clients, camelCase might be more natural. If your backend is Python or Ruby, snake_case avoids constant conversion. Most API style guides recommend snake_case (Google's JSON style guide being a notable exception).
HTTP Headers
Content-Type: application/json
X-Request-Id: abc-123
Authorization: Bearer token
HTTP headers use their own convention: capitalized words separated by hyphens. This is defined by the HTTP specification.
Environment variables
# SCREAMING_SNAKE_CASE
DATABASE_URL=postgres://localhost/mydb
API_SECRET_KEY=sk_live_abc123
MAX_WORKERS=4
This is universal across operating systems and languages.
Converting between conventions
When working across language boundaries (e.g., a Python API consumed by a JavaScript frontend), you'll need to convert between conventions. Most languages have libraries for this:
// JavaScript: change-case npm package
import { camelCase, snakeCase } from 'change-case';
camelCase('user_id'); // "userId"
snakeCase('userId'); // "user_id"
# Python: inflection or humps
import humps
humps.camelize({'user_id': 42}) # {'userId': 42}
humps.decamelize({'userId': 42}) # {'user_id': 42}
For quick one-off conversions when you're working with data transformations or writing documentation, textshifter.com/tools/case-converter handles all common conventions. Paste text in one format, get it in another.
The rules that actually matter
- Follow your language's convention. Don't use camelCase in Python or snake_case in JavaScript. Your code should look like it belongs.
- Be consistent within a project. Mixing conventions in the same codebase is worse than picking the "wrong" one.
- Match the boundary. Use the convention of whatever system you're interfacing with. Database columns get snake_case. HTTP headers get Title-Kebab-Case. Environment variables get SCREAMING_SNAKE_CASE.
- Don't fight your framework. If Rails wants snake_case and React wants camelCase, convert at the API boundary. Don't force one convention where it doesn't belong.
- Use your linter. ESLint, Pylint,
go vet, and Clippy all enforce naming conventions. Let the tooling catch inconsistencies so code reviews can focus on logic.
Naming conventions aren't about personal preference. They're about making code readable for the next person who touches it -- which is often you, six months from now.