ENES
case-conversionEngineering Guide

Converting Between camelCase, snake_case, and kebab-case: Rules and Gotchas (2026)

AC
Alex ChenΒ·Lead Systems Architect
Published on 2026-09-02Β·8 min readΒ·Daily Toolbox Engineering

Converting Between camelCase, snake_case, and kebab-case: Rules and Gotchas (2026)

You're migrating an API from snake_case (Python backend) to camelCase (JavaScript frontend). You write a quick converter. It works for user_name β†’ userName. Then it mangles get_HTTP_response into getHttpResponse or getHTTPResponseβ€”and you're not sure which is right.

Case conversion looks trivial until you hit acronyms, numbers, and edge cases. A naive converter breaks on real-world identifiers.

This guide covers the exact conversion rules between the major naming conventions, the acronym problem, and copy-paste-ready code that handles the gotchas.


The Five Naming Conventions

Convention Example Used In
camelCase firstName JavaScript, Java variables
PascalCase FirstName Classes, React components, C#
snake_case first_name Python, Ruby, SQL, databases
kebab-case first-name URLs, CSS, HTML attributes
SCREAMING_SNAKE FIRST_NAME Constants, env variables

Where Each Matters

  • JavaScript objects/JSON: camelCase (userId, createdAt)
  • Python/database columns: snake_case (user_id, created_at)
  • CSS classes/URLs: kebab-case (main-nav, /blog-post)
  • Constants: SCREAMING_SNAKE (MAX_RETRIES, API_KEY)
  • Class names: PascalCase (UserProfile, HttpClient)

Conversion Rules

The Universal Approach: Split, Then Join

All case conversion follows two steps:

  1. Split the identifier into words
  2. Join the words in the target format

The hard part is step 1 (splitting correctly).

Splitting Rules by Source Format

Source Split On
snake_case underscores _
kebab-case hyphens -
camelCase / PascalCase before each uppercase letter
SCREAMING_SNAKE underscores, then lowercase

Joining Rules by Target Format

Target Join Method
camelCase first word lowercase, rest capitalized, no separator
PascalCase all words capitalized, no separator
snake_case all lowercase, joined with _
kebab-case all lowercase, joined with -
SCREAMING_SNAKE all uppercase, joined with _

The Acronym Problem

Why Naive Conversion Breaks

Consider converting getHTTPResponse to snake_case.

Naive rule ("insert _ before each uppercase"):

get_H_T_T_P_Response  ← wrong! acronym shattered

What you actually want:

get_http_response

The Ambiguity

There's no universal "correct" answer for acronyms because the source loses information:

snake_case Could become camelCase
get_http_response getHttpResponse OR getHTTPResponse
parse_url parseUrl OR parseURL
user_id userId OR userID

Both are used in practice. Google's JavaScript style guide says treat acronyms as words (getHttpResponse). Others preserve them (getHTTPResponse).

Recommended: Treat Acronyms as Words

The most consistent, least buggy approach (Google style):

  • HTTP β†’ Http
  • getHTTPResponse β†’ get_http_response β†’ getHttpResponse
  • userID β†’ user_id β†’ userId

This makes conversion reversible and predictable.


Copy-Paste Converters (JavaScript)

Split any identifier into words

function splitWords(str) {
  return str
    // handle camelCase/PascalCase boundaries
    .replace(/([a-z])([A-Z])/g, '$1 $2')
    // handle acronym followed by word: HTTPResponse -> HTTP Response
    .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
    // handle letter-number boundaries
    .replace(/([a-zA-Z])([0-9])/g, '$1 $2')
    // replace separators with spaces
    .replace(/[_-]+/g, ' ')
    .trim()
    .toLowerCase()
    .split(/\s+/);
}

// splitWords("getHTTPResponse")  -> ["get", "http", "response"]
// splitWords("user_id")          -> ["user", "id"]
// splitWords("main-nav-bar")     -> ["main", "nav", "bar"]

Convert to each format

function toCamelCase(str) {
  const words = splitWords(str);
  return words[0] + words.slice(1)
    .map(w => w[0].toUpperCase() + w.slice(1))
    .join('');
}

function toPascalCase(str) {
  return splitWords(str)
    .map(w => w[0].toUpperCase() + w.slice(1))
    .join('');
}

function toSnakeCase(str) {
  return splitWords(str).join('_');
}

function toKebabCase(str) {
  return splitWords(str).join('-');
}

function toScreamingSnake(str) {
  return splitWords(str).join('_').toUpperCase();
}

// toCamelCase("get_http_response")  -> "getHttpResponse"
// toSnakeCase("getHTTPResponse")    -> "get_http_response"
// toKebabCase("MainNavBar")         -> "main-nav-bar"

Python Equivalents

import re

def split_words(s):
    s = re.sub(r'([a-z])([A-Z])', r'\1 \2', s)
    s = re.sub(r'([A-Z]+)([A-Z][a-z])', r'\1 \2', s)
    s = re.sub(r'([a-zA-Z])([0-9])', r'\1 \2', s)
    s = re.sub(r'[_-]+', ' ', s)
    return s.strip().lower().split()

def to_camel(s):
    words = split_words(s)
    return words[0] + ''.join(w.capitalize() for w in words[1:])

def to_snake(s):
    return '_'.join(split_words(s))

def to_kebab(s):
    return '-'.join(split_words(s))

# to_camel("get_http_response")  -> "getHttpResponse"
# to_snake("getHTTPResponse")    -> "get_http_response"

Edge Cases That Break Converters

1. Numbers in identifiers

address2         β†’ address_2 or address2?
oauth2Token      β†’ oauth_2_token or oauth2_token?

Recommendation: Keep numbers attached to preceding word unless clearly separate: oauth2_token.

2. Consecutive separators

user__name       β†’ user_name (collapse doubles)
--main--nav--     β†’ main-nav (trim and collapse)

Fix: Use [_-]+ (one-or-more) in split regex, and .trim().

3. Leading/trailing separators

_private         β†’ private? or _private (preserve)?

Note: In Python, leading underscore is semantic (private). Don't strip it if it carries meaning.

4. All-caps acronym alone

URL              β†’ url (snake) β†’ url (camel)?
API              β†’ api

Handled correctly by treating acronyms as words.

5. Mixed with special characters

first.name       β†’ depends: split on . too?
user@domain      β†’ usually leave @ alone

Decide explicitly what your separators are.


Conversion Matrix (Quick Reference)

Starting from user_profile_id:

Target Result
camelCase userProfileId
PascalCase UserProfileId
snake_case user_profile_id
kebab-case user-profile-id
SCREAMING_SNAKE USER_PROFILE_ID

FAQ

Q: Is it userId or userID?
A: Both are used. Google's style guide recommends userId (acronyms as words) for consistency and reversible conversion. Pick one and stay consistent.

Q: How do I convert API JSON (snake_case) to JavaScript (camelCase) automatically?
A: Libraries like humps (JS) or camelize do this recursively for objects. Or write a recursive key-mapper using the converters above.

Q: Why does my converter turn HTTPResponse into h_t_t_p_response?
A: Your regex inserts a boundary before every uppercase letter. Add the acronym rule: ([A-Z]+)([A-Z][a-z]) to keep consecutive capitals together.

Q: Should CSS use kebab-case or camelCase?
A: CSS properties and classes use kebab-case (background-color, .main-nav). In JavaScript accessing CSS, they become camelCase (element.style.backgroundColor).

Q: What about database columns?
A: Most SQL databases are case-insensitive and conventionally use snake_case (created_at, user_id) to avoid quoting.


Conclusion

Case conversion is straightforward once you handle the gotchas:

  1. Split then join β€” the universal two-step approach
  2. Handle acronyms β€” treat HTTP as one word, not four letters
  3. Watch numbers β€” decide if address2 splits or not
  4. Collapse separators β€” use [_-]+ and .trim()
  5. Stay consistent β€” pick userId or userID and never mix

Use the copy-paste converters above; they handle camelCase, snake_case, kebab-case, PascalCase, and SCREAMING_SNAKE with correct acronym and number handling.

#case-conversion#camelcase#snake-case#naming-conventions
AC
Written by Alex ChenLead Architect

Alex Chen is a distributed systems engineer and core maintainer at Daily Toolbox with over 10 years of experience in client-side web technologies, RFC standards compliance, and cryptographic protocols. He specializes in zero-knowledge client architectures and WebAssembly-accelerated algorithms.

Try the free tools mentioned above

⚑ Open Text Case Converter β†’