Regex to Convert camelCase to snake_case

Regex pattern to convert camelCase identifiers to snake_case. Handles consecutive capitals (XMLHttpRequest), digits, and PascalCase. Useful for codebase migrations.

Replace and Format

Detailed Explanation

camelCase to snake_case

Converting camelCase to snake_case is a frequent step when migrating between languages or naming conventions (JavaScript camelCase to Python snake_case, for example).

Basic Conversion

str.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase()

Inserts an underscore between a lowercase or digit and the next uppercase letter, then lowercases everything.

Handle Consecutive Capitals

The basic version turns XMLHttpRequest into x_m_l_http_request. To get xml_http_request:

str
  .replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
  .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
  .toLowerCase()

The first replace splits runs of capitals before a capital-then-lowercase boundary; the second handles the standard case.

Tested Examples

Input Basic Two-Pass
fooBar foo_bar foo_bar
getUserName get_user_name get_user_name
URLPath u_r_l_path url_path
XMLHttpRequest x_m_l_http_request xml_http_request
PascalCase pascal_case pascal_case
apiV2Endpoint api_v2_endpoint api_v2_endpoint

Convert to kebab-case Instead

Replace the underscore with a hyphen:

str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase()

Handle Numbers Adjacent to Letters

If you want apiV2 to become api_v_2 (separating letter from digit), add a third pass:

str.replace(/([a-zA-Z])(\d)/g, "$1_$2")

Practical Recommendation

For simple identifiers, the two-pass version handles every realistic input correctly. For database column migrations, write tests covering acronyms (URL, API, HTTP), digits, and pre-existing underscores.

Use Case

Migrating a JavaScript codebase’s camelCase API to a Python backend that expects snake_case, or converting database column names during a Rails-to-Django port.

Try It — Regex Cheat Sheet

Open full tool