Notes › Tech Notes › Mixed casing styles: batch-converting camelCase, snake_case and more

Mixed casing styles: batch-converting camelCase, snake_case and more

Last year I integrated with a seven-year-old system and saw four spellings of the same field: the database had created_time, the API document said CreateTime, the front-end type definition had createTime, and the analytics spreadsheet called it Created Time. The first version of the code could not read the value, and I spent over two hours suspecting serialization, then the gateway, then time zones, before finding that the mapUnderscoreToCamelCase switch in the ORM was off. Since then I treat name-style conversion as a job that needs a tool, not as a quick tweak.

1. One word, several shapes

Naming style is not an aesthetic question, it is the historical convention of each stack. The same user name has different legal spellings in different places:

StyleExampleMostly seen in
camelCaseuserNameJavaScript and Java variables and methods, GraphQL fields
PascalCaseUserNameClass names, React components, C# public members
snake_caseuser_namePython variables and functions, database column names
CONSTANT_CASEUSER_NAMEConstants, environment variables
kebab-caseuser-nameURL paths, CSS class names, CLI flags
Title CaseUser NameTable headers, button labels, report column names

External APIs have no shared standard either: GitHub's public API uses snake_case almost everywhere, and Google-style APIs use camelCase. So the same data passing through three layers gets converted three times. The risk in doing it by hand is not slowness but inconsistency: in a batch of 42 fields, one slip that produces both userName and username means that field maps differently from the rest, and that kind of difference usually surfaces at runtime.

2. Name collisions usually blow up in four places

  • Database identifier case. PostgreSQL folds unquoted identifiers to lowercase, so a column created as CreateTime is actually stored as createtime, and every later reference needs double quotes. Whether MySQL table names are case-sensitive depends on server configuration and the filesystem: sensitive on Linux, usually insensitive on Windows, so it works on my machine and the server says the table does not exist can both be true at once.
  • HTTP headers. Header names are case-insensitive by specification, and many runtimes read them all as lowercase, turning Content-Type into content-type; after a gateway rewrite the value is missing, and most people go looking at authentication first.
  • Signatures and canonical strings. Field names that take part in a signature must match the other side character for character. Convert AppKey to appkey and verification fails, and the error only says invalid signature, never that case is the problem.
  • Abbreviations and digits. userID or userId, QrCode or QRCode, and utf8mb4 turned into Utf8Mb4 by a camel-case pass; mechanical conversion often looks worse than the original. Words like these need a manual allow-list rather than a rule that guesses.

There is one more trap few people guard against in advance: case conversion is not a reversible letter mapping in every locale. In Turkish the lowercase of uppercase I is the dotless ı, not i; in Java, toLowerCase() without Locale.ROOT hits exactly this, so a field name is fine in the test environment and stops matching once deployed to a machine with a regional setting.

3. How I do bulk conversion now

  1. Normalise the separators first. Field names may mix spaces, underscores and hyphens, so I start with Batch Find and Replace and one regex rule that turns [_\-\s]+ into a single underscore, giving the later conversion stable input.
  2. Paste the whole column into Case Converter and take uppercase, lowercase, capitalised, camelCase, snake_case and kebab-case outputs. 42 rows are handled at once, and each of the three target naming schemes takes one column; what this saves compared with editing one by one is not only time but error rate.
  3. Check the result with a regex before it goes into the document. Use Regex Tester with a pattern such as ^[a-z][a-z0-9]*(_[a-z0-9]+)*$; whatever rows fail are fields where the conversion could not find the word boundaries, usually abbreviations or glued-on digits, and those get handled by hand.
  4. Bake the rules into checks rather than conventions. The front end gets ESLint's camelcase rule, Python gets the linter's naming checks, and database column names are written as snake_case in the migration review checklist. The converter handles what exists; lint handles what is added.
  5. Propagate the rename downstream: views, BI reports, export templates and the lookup tables the ops team maintains all need regenerating under the new names. The most easily missed item in an old system is an Excel query template someone maintains by hand.

4. A few boundaries

Case and naming style only apply to Latin letters. Chinese text, full-width letters and Chinese comments in code are not converted and not damaged, but when mixed text is processed in bulk the comments change format with it, so I usually paste only the field list, never a whole source file.

Do not turn an entire source file into uppercase or lowercase for the sake of consistency. Readability and diff noise are both costs; the correct scope is identifiers, table headers and constant names, while prose copy follows sentence case separately.

Renaming a public contract needs a transition period. A field-level rename is a breaking change for callers, so the usual approach is to output the new and old names in parallel for one release cycle and note the deprecation date in the documentation.

5. Common questions

Q: How do I choose between camelCase and PascalCase?

Ask whether it is a type. Class, component and interface names use PascalCase; instances, variables, methods and function parameters use camelCase. That is the shared convention of the Java, JavaScript and C# communities.

Q: What naming should database columns use?

snake_case is more stable: portable across databases, no dependency on quoting, and the most readable in SQL. Once it is decided, let the ORM's automatic conversion handle the mapping to camelCase in code instead of aligning both sides by hand.

Q: Why does code that works locally report a missing field on the server?

Most likely a difference in case sensitivity. Windows filesystems are insensitive and Linux is sensitive, and database table and column behaviour follows configuration and platform. Normalising identifiers to lowercase with underscores avoids this class of platform dependency at the root.

Q: Can dozens of header rows be converted in one pass?

Yes, bulk multi-line processing is the reason these tools exist. The points are to normalise the separators first, choose the target style, and validate the output with one regex; none of the three steps can be skipped.

Q: Does conversion affect strings that are already encrypted or signed?

It changes the source text that goes into the calculation, so the result is completely different. Signature, hash and Base64 strings always stay as they are; only human-written identifiers get converted, and the two should never be in the same batch.

I later did a full rename of that old system: everything in the database is snake_case, API output is uniformly camelCase, and front-end types are generated from the API definition rather than hand-written. Looking back, the root cause of those two hours was not a mistake in any single layer, but that nowhere was it written down what this field should look like at this layer. Naming style itself is neither right nor wrong; mixing them is what costs you.

📎 Related articles

PNG compressed three times only lost 426 bytes: the real boundary of lossless compression 2026-10-22 How Many Times Bigger a PNG Gets After Converting From WebP: When It Is Unavoidable and How to Keep the Growth Down 2026-10-22 Three Reasons the Small Text Smudges When a Screenshot Is Shrunk to a Quarter 2026-10-22 Cropped to the Same 300x300, Why Does the Avatar Always Sit Half a Cell Low-Right 2026-10-22 Forecasting 18 months at 1.7 times a month: why the script and the sheet give two numbers 2026-10-22