Skip to main content

CLI

hclschema <command> [flags] [files...]
CommandPurpose
validateCheck HCL files against their schemas
fmtRewrite schema documents in canonical form
inferDerive a starting schema from existing files
docsRender Markdown reference documentation
bundleInline imports into one self-contained document
lspRun the language server
versionPrint the version

Exit codes​

CodeMeaning
0No error diagnostics
1At least one error was reported
2Usage problem, or a file could not be read

Separating "found problems" from "could not run" is what lets a CI job tell a failing check apart from a broken invocation.

Shared flags​

FlagDefaultMeaning
--strictfalseApply draft 2026-09 rules regardless of what a schema pins
--offlinefalseNever reach the network; serve remote schemas from the cache only
--cache-dirper-user cache dirWhere cached remote schemas live
--timeout15sTimeout for a single remote fetch

validate​

hclschema validate [flags] [files or directories...]

With no arguments the current directory is walked. Directories are walked recursively for .hcl and .hcl.json files, skipping .git, node_modules, vendor and .terraform. A pattern that your shell did not expand is treated as a glob.

A *.schema.hcl file is checked against the meta-schema rather than against a schema of its own.

FlagMeaning
--schema <path>Validate against this schema instead of each file's __schema
--format <fmt>text (default), json, github or sarif
--stdin-filename <name>Read the document from stdin, report it under this name
--exit-zeroAlways exit 0
--warn-as-errorCount warnings toward the exit code
--quietReport only errors
--no-colorDisable colour in text output
--recursiveWalk directories (default true)

Output formats​

text uses HCL's own diagnostic writer, so you get the offending line with a caret under the range:

Error: Value above maximum

on config/service.hcl line 6, in listener "https":
6: port = 99999

"port" has 99999, above the maximum of 65535.

json emits an array with zero-based positions, the shape the editor integration consumes:

[
{
"file": "/abs/path/config/service.hcl",
"startLine": 5,
"startCol": 9,
"endLine": 5,
"endCol": 14,
"severity": "error",
"message": "Value above maximum: \"port\" has 99999, above the maximum of 65535.",
"summary": "Value above maximum",
"detail": "\"port\" has 99999, above the maximum of 65535."
}
]

github emits workflow commands, which appear as inline annotations on a pull request with no extra action:

::error file=config/service.hcl,line=6,col=10,endLine=6,endColumn=15::Value above maximum: ...

sarif emits SARIF 2.1.0 for GitHub code scanning. See CI.

Checking a buffer​

hclschema validate --stdin-filename config/service.hcl < buffer.hcl

The name is used to resolve a relative __schema and to report positions; the content comes from stdin. This is how an editor checks unsaved work — though the language server is the better answer for that.

fmt​

hclschema fmt [-w] [--check] [files...]

Parses each *.schema.hcl and re-renders it through hclwrite, which normalises key order, spacing and indentation. Rendering is idempotent, so --check is meaningful:

FlagMeaning
-wRewrite the file in place
--checkList unformatted files and exit 1; write nothing
--forceFormat a file even though its comments would be lost

Without -w or --check, the result goes to stdout.

Comments

Formatting works by parsing and re-rendering, and HCL's parse tree holds no comments. A file containing comments is therefore skipped, with a note on stderr, rather than silently stripped. --force formats it anyway and loses them.

infer​

hclschema infer [flags] <files or directories...>

Derives a schema from existing documents. It reads the native-syntax parse tree directly, so JSON samples are skipped with a warning.

FlagMeaning
--id <id>Value for the generated __id
-o <path>Write to a file instead of stdout
--required-when-ubiquitousMark an attribute required when every sample has it

Inference deliberately does not guess: where samples disagree on a type, no type is emitted, because a wrong constraint would reject a file that is actually fine. Treat the output as a first draft.

docs​

hclschema docs [flags] <schema.hcl>
FlagMeaning
--title <text>Document title (default: the schema's __id)
-o <path>Write to a file instead of stdout
--heading-offset <n>Shift every heading down, for embedding
--no-frontmatterOmit the Docusaurus front matter

The output carries Docusaurus front matter by default, so it drops straight into a docs site:

hclschema docs service.schema.hcl -o website/docs/reference/service.md

bundle​

hclschema bundle [flags] <schema.hcl>

Writes one self-contained document with no import blocks. Shared and recursive bodies get a generated id and are emitted once. Use it to vendor a schema so that validation needs no network access.

lsp​

hclschema lsp [flags]

Speaks LSP over stdin and stdout. See Editors.