flashman
← All guides

Split identifiers before you change their case

Convert camel case, snake case, and kebab case with the splitter each output actually uses, and keep acronyms and separators intact before you rename a field.

2026-10-18 · 8 min read

  • naming
  • json
  • api

Renaming a field at an API boundary is a split, a case change, and a join. The three outputs in Flashman's case tool do not share one splitter, so a value that looks converted can be a different identifier with the same letters.

Camel case trims, splits on one or more spaces, underscores, or hyphens, drops empty pieces, lowercases each piece, and capitalizes every piece after the first. It never splits on a capital letter. Snake case inserts an underscore only where a lowercase letter or a digit is followed by a capital, replaces spaces and hyphens with underscores, and lowercases. Kebab case uses that capital boundary, then replaces spaces and underscores with a single hyphen.

Leave existing camel case out of the camel box

maxTorque has no separator, so camel case prints maxtorque. Snake case sees the eT boundary and prints max_torque. Kebab case prints max-torque. fooBarBaz becomes foobarbaz, foo_bar_baz, and foo-bar-baz. If you need the snake form of a camelCase name, paste the camelCase name into the tool once and copy the snake box. Pasting the camel box's output back in has already deleted the capitals.

The reverse direction is safer when the separators are real. api_key and already-kebab become apiKey and alreadyKebab. API_KEY becomes apiKey because the underscore is a split. A second conversion is not required, and it is how acronyms get flattened twice.

  • Paste the original identifier, not a previous output.
  • Copy one box and stop.
  • Treat a run of capitals as one word unless a lowercase letter breaks it.
  • Write the chosen form next to the JSON key it replaces.

Acronyms and separators follow the code, not the dictionary

XMLHttpRequest becomes xmlhttprequest in camel case. Snake case inserts a boundary only at pR and prints xmlhttp_request. HTTPResponse has no lowercase-then-uppercase pair, so every box prints httpresponse. getHTTPResponse becomes get_httpresponse. userID becomes user_id, which looks right, while userIDNumber becomes user_idnumber, which glued Number to ID because only the rI boundary was inserted.

Repeated underscores are not one rule. a__b stays a__b in snake case and becomes a-b in kebab case. _private stays _private in snake case, becomes -private in kebab case, and becomes private in camel case because the empty piece is dropped. 123abc is not rejected. A leading digit is still illegal in most languages, and the tool will not tell you.

Case folding is Unicode default case

The tool calls toLowerCase, not toLocaleLowerCase. An ASCII I becomes i in every locale, including Turkish, where a locale-aware fold would produce a dotless ı. The Turkish capital İ, U+0130, becomes the two code points U+0069 and U+0307. The camel, snake, and kebab results of İstanbul look like istanbul and are not equal to the ASCII result of ISTANBUL.

ß stays ß. The tool never uppercases, so it will not expand ß to SS. If a database collation folds these letters differently from the tool, the rename will not match the rows you think it matches. Compare the code points when a visual diff looks clean.

Review the key inside the payload

Format the JSON, copy the key, and run the case tool on that exact string. Diff the selected output against the key the consumer already accepts. A round trip from snake case back through camel case recovers fooBarBaz from foo_bar_baz. A round trip that starts by camel-casing fooBarBaz does not, because the first step prints foobarbaz.

Keep the input, the three outputs, and the one output you will ship in the change note. The JSON formatter shows the surrounding object. The case tool shows the split. Diff shows whether the new key is the one the other side already stores.

Try these tools