Terraform Resource Name Converter
snake_case writes hello_world_example. Terraform identifiers must start with a letter or underscore and may contain only letters, digits, underscores and hyphens — and the community convention is snake_case throughout, for resource names, variables, outputs and locals. Hyphens are legal but awkward, because a resource address like aws_instance.web-server needs care in interpolation where web_server does not.
Conversions
| Input | snake_case |
|---|---|
hello world example | hello_world_example |
XMLHttpRequest | xml_http_request |
user_first_name | user_first_name |
Total Order Count | total_order_count |
XMLHttpRequest becomes xml_http_request. That uniformity is why snake_case survives round-tripping better than the camel family — there is no capitalisation left to get wrong on the way back.The Same Text in Other Cases
| Case | Result |
|---|---|
| camelCase | helloWorldExample |
| PascalCase | HelloWorldExample |
| SCREAMING_SNAKE_CASE | HELLO_WORLD_EXAMPLE |
| kebab-case | hello-world-example |
| Train-Case | Hello-World-Example |
| dot.case | hello.world.example |
Resource Names Become Addresses
A resource name is half of its address in state: aws_instance.web_server. That address appears in plan output, in depends_on, in terraform state mv, and in every interpolation referencing the resource.
Hyphens are legal in the name but awkward in an address, and renaming is not cosmetic — Terraform reads it as destroying one resource and creating another unless you move the state explicitly. Getting the name right before the first apply is worth the minute it takes.
Converting in Code
``javascript
const snake = (s) => words(s).map((w) => w.toLowerCase()).join('_');
`
The failure mode is on the way *in*, not out. A converter that splits only on existing underscores turns userId into userid rather than user_id, and the mistake is invisible until someone searches for a column that does not exist.
Converting at the API Boundary
The recurring friction is that JavaScript uses camelCase and Python, Ruby, Go and SQL use
snake_case. The fix is to convert in exactly one place — the client that talks to the API —
rather than letting both conventions into the same codebase.
`javascript
const toCamel = (s) => s.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
const toSnake = (s) => s.replace(/[A-Z]/g, (c) => '_' + c.toLowerCase());
// Recursively, for a whole payload
const convertKeys = (value, fn) =>
Array.isArray(value)
? value.map((v) => convertKeys(v, fn))
: value && typeof value === 'object'
? Object.fromEntries(Object.entries(value).map(([k, v]) => [fn(k), convertKeys(v, fn)]))
: value;
`
Two things to watch: keys that are user data rather than field names must not be
converted, and the round trip is not always lossless — userID → user_id → userId
changes the original.
Where Each Convention Is Mandatory
Not stylistic — these will break if you deviate:
| Context | Requirement |
|---|---|
| Environment variables | Uppercase with underscores; POSIX reserves lowercase |
| Custom HTML elements | Must contain a hyphen |
| Python modules | Cannot contain hyphens; the import statement will not parse |
| SQL identifiers | Folded to one case unless quoted, so camelCase does not survive |
| React components | Must start uppercase, or JSX treats it as an HTML tag |
Renaming Safely
A find-and-replace across a codebase will hit strings, comments and unrelated identifiers.
Use your language server's rename symbol instead — it understands scope. For a bulk rename
across files, restrict the pattern with word boundaries and review the diff before
committing:
`bash
grep -rn '\buserId\b' src/ # look first
``