Terraform Formatter & Validator (fmt, HCL ⇄ JSON)
Format Terraform and OpenTofu files the fmt way, check the module and see how it connects.
Try before you buy.
- Free preview: the first lines of each formatted file and its JSON (up to 20), every count with the first findings (up to 10), and the graph under a MySmartCoPilot mark.
- Locked until you unlock it: download and copy.
- Unlock: Pro pass, ₹179 for 30 days or ₹79 for 1 week, a one-time payment that never renews. Unlock: Pro pass, $5.99 for 30 days or $2.99 for 1 week, a one-time payment that never renews.
Ways to unlock shows how to get the full result.
Printing this result is locked in the free preview.
Configuration
The name tells the kind: .tf, .tfvars, .tftest.hcl, .tf.json or .tfstate. Folders (modules/vpc/main.tf) are child modules.
Checked as you type, in your browser. Ctrl/⌘ + Enter checks now.
Files
| File | Kind | Size | Result |
|---|
- Resource
- Data source
- Module
- Variable, local or output
- Arrows point from what is needed to what uses it; bold ones come from
depends_on.
Dependencies
| Needed | Used by | How |
|---|
Secrets kept in plain text
Resources
| Address | Provider | Instances |
|---|
Outputs
| Output | Type | Value |
|---|
Locked in the free preview. Opens the ways to unlock this result.
Locked in the free preview. Batch runs unlock with a pass.
Locked in the free preview. Query results unlock with a pass.
About the Terraform Formatter & Validator (fmt, HCL ⇄ JSON)
Paste a .tf file, or open several files or a ZIP of a module (up to 5 MB): every file is laid out in Terraform’s canonical style, the way terraform fmt and tofu fmt write it — two spaces per level, the = signs of neighbouring arguments aligned, one space around operators and inside braces, none inside brackets — with labels quoted, "${var.x}" unwrapped to var.x and legacy types such as "string" turned into string. Syntax errors are reported with their line and column, and the file is left as it is, as fmt does.
The module is then checked as a whole: duplicate blocks, references to variables, locals, modules, resources or data sources it does not declare, a missing required_version, providers without a version constraint, module sources that are not pinned (git without ?ref=, the registry without version), variables without a type or description, secret-looking defaults and keys written into the code, count together with for_each, and pre-0.12 syntax. Each finding says how to fix it. You can also convert files to Terraform’s JSON syntax and back, see the dependency graph of resources, data sources and modules drawn from their references, and open a terraform.tfstate to list its resources and outputs and the secrets it keeps in plain text.
Everything runs in your browser; nothing is uploaded. Without a pass the result is a free preview: the first lines of each formatted file, every count with the first findings, and the graph under a mark. Whole files, every finding, the ZIP of formatted files and every copy and download unlock with a Pro pass.
How to use it
- Paste a file, open
.tf,.tofu,.tfvars,.tftest.hcl,.tf.jsonor.tfstatefiles, or open a.zipof the module (folders become child modules). Load example shows a small module with typical problems. - Read the Formatted tab: the diff of what formatting changes, or the whole file. Choose another file of the module in the file list.
- Open Findings for errors, warnings and notes, each with its file, line, the reason and the fix; Show selects the line in the editor.
- Open Graph to see what depends on what (arrows point from a resource to the ones that use it); turn on variables, locals and outputs to see them too.
- Open JSON for the file in Terraform’s JSON syntax, or open a
.tf.jsonfile to get it as native HCL; State lists what a state file holds. - Copies and downloads — the formatted file, a ZIP of every formatted file, the findings report, the graph as PNG, DOT or Mermaid, and the JSON — unlock with a Pro pass; the free preview shows their first lines.
Examples
resource aws_instance "web" {
ami = "ami-123"
instance_type="t3.micro"
}resource "aws_instance" "web" {
ami = "ami-123"
instance_type = "t3.micro"
}vpc_id = "${module.vpc.vpc_id}"
variable "name" {
type = "string"
}vpc_id = module.vpc.vpc_id
variable "name" {
type = string
}resource "aws_instance" "web" {
count = 2
for_each = toset(var.zones)
}Error (count-and-for-each), main.tf:3 — sets both "count" and "for_each"; Terraform accepts only one of them. Fix: keep for_each for one instance per key, or count for N identical instances.
What formatting changes, and what it never touches
The layout follows the conventions of Terraform’s style guide and the behaviour of terraform fmt: indentation by bracket level, aligned = signs for consecutive single-line arguments (a value that opens a bracket or a blank line ends the group), aligned trailing comments, and normalised spaces between tokens. Besides whitespace it makes only Terraform’s own rewrites: quoted block labels, a "${…}" that is the whole value unwrapped (in parentheses when it spans lines), and the legacy variable types "string", "list" and "map" (and a bare list, map or set) written as type expressions. The text of strings, heredocs and comments, blank lines and a missing final newline stay as they are, and // comments are not rewritten to # (that one is reported as a note instead).
The checks
- Errors Terraform would refuse: duplicate resources, data sources, modules, variables or outputs; a provider configured twice without different aliases; duplicate local values; references to things the module does not declare;
countandfor_eachtogether; a block in an override file with nothing to override. - Warnings: no
required_version; providers without a version constraint inrequired_providers; registry modules withoutversionand git modules without?ref=; variables without atype; secret-looking variable defaults; keys and tokens written into the code (AWS access keys, private keys, GitHub, Slack, Stripe and Google API keys); quoted references independs_onandprovider. - Notes: variables without a description, interpolation-only strings and legacy types (which formatting fixes),
//and/* */comments, names with capitals or dashes.
Each folder is a module of its own, as in Terraform. Override files (override.tf and any *_override.tf) are merged into the blocks of the other files, as Terraform merges them, so their blocks are not duplicates. A single pasted file is checked on its own, so references to things declared in its other files are warnings, not errors.
JSON syntax, the graph and state files
The JSON conversion follows Terraform’s JSON configuration syntax: one nested object per block label, arrays for repeated blocks and provisioners, expressions as "${…}" templates, and the arguments Terraform takes literally written as they are: a variable’s type, default and description, a module’s source, version and providers map. References are plain strings such as "aws_instance.web": depends_on, provider, ignore_changes, replace_triggered_by, and the addresses of moved, removed and import blocks. Going back from JSON, nested blocks of a provider cannot be told from map arguments without the provider’s schema, so lists of objects become blocks and every such guess is listed.
The graph is drawn from the references in each block and from depends_on; a dependency through a local value or a variable shows as an edge between the things it connects. State files (format version 4, written by Terraform 0.12 and later and by OpenTofu) list each resource with its instances, the outputs, and the attributes kept in plain text: those the provider marks sensitive, sensitive outputs, and attributes named like secrets. Their values are shown masked.
Limitations
- The formatter is MySmartCoPilot’s own implementation of the canonical style, matched against the reference formatter’s published examples; Terraform may add formatting rules in a new version.
- The checks read the configuration only: providers are not downloaded, so provider arguments, resource types and values are not validated (
terraform validatedoes that with the providers installed). - References into child modules (
module.x.output) are checked for the module, not for the output; outputs of a remote module are not known. - Up to 5 MB of files at a time; the graph is easiest to read with a few hundred resources at most.
Privacy
On this device: nothing is sent
Everything happens in your browser. What you enter or open here is not uploaded or stored by MySmartCoPilot.
Frequently asked questions
What do I get without a pass?
Without a pass, Terraform Formatter & Validator (fmt, HCL ⇄ JSON) shows the first lines of each formatted file and its JSON (up to 20), every count with the first findings (up to 10), and the graph under a MySmartCoPilot mark. Until you unlock it, the result can’t be downloaded or copied. A Pro, Premium or Ultimate pass, a one-time payment that never renews, unlocks the full result. The pricing page lists the passes and their prices.
Is the result the same as terraform fmt?
It applies the same rules: the layout of the reference formatter (checked against its published examples) and Terraform’s own rewrites of labels, interpolation-only strings and legacy types. Like fmt, it refuses a file with syntax errors and leaves it unchanged. Run terraform fmt -check in CI if you need the exact version of Terraform you use to be the judge.
Does it work with OpenTofu?
Yes. OpenTofu uses the same language and the same formatting, and .tofu and .tofutest.hcl files are read like .tf and .tftest.hcl files.
Why is a variable reported as undeclared when it exists?
The checks see only the files you give them. Variables usually live in variables.tf: open all the module’s files together, or a ZIP of the folder, so the declarations are found. A single pasted file reports such references as warnings for this reason.
Why does it warn about secrets in my state file?
Terraform stores every attribute of every resource in the state, including passwords and keys, without encrypting them. Keep state in a backend that encrypts it and limits who can read it, mark variables and outputs sensitive, and prefer short-lived credentials. The page lists such values masked; nothing leaves your browser.
Is my configuration uploaded?
No. Files, ZIPs and state files are read and processed in your browser only.