Fast, offline, embeddable validation for AWS CloudFormation templates.
cloudformation-validate parses a CloudFormation template (JSON or YAML) and returns structured diagnostics - schema
violations, semantic errors, security concerns, and best-practice suggestions - before you deploy. It runs entirely
offline: every rule and resource schema is compiled into the binary, so there is no network access, no credentials, and
no runtime fetching.
It ships as a Rust CLI, an embeddable Rust library, a Node.js package (WASM), a Python package, a Go module, and a JVM library (Kotlin/Java) - all backed by the same validation core.
- Offline-first. Rules and AWS resource schemas are baked into the binary. Nothing is fetched at runtime.
- Structured diagnostics. Every finding carries a stable rule ID, severity, precise source span (line/column), resource path, and an optional suggested fix - designed for IDEs, CI, and agents, not just humans.
- Standalone engines. The Rego and CEL engines independently evaluate the same built-in rule set and produce identical results.
- Composite engine (default). CEL evaluates every built-in rule while a separate external-only Rego engine
evaluates your custom Rego and translated Guard rules, layered on top. It is additive - with no custom rules it
produces the same diagnostics as the standalone Rego and CEL engines - and it is the default engine. Select a
standalone engine with
--engine rego/--engine cel, or buildRegoEngine/CelEnginedirectly when embedding. - Additional schemas. Merge your own CloudFormation resource provider schemas on top of the bundled ones, so
templates using properties or values CloudFormation has not published yet validate cleanly
(
--additional-schema, orEngineConfig.schema_validator_config.additional_schemaswhen embedding). - Custom rules. Extend validation with your own rules in CEL (JSON), Rego, or CloudFormation Guard DSL.
- AWS CLI command validation. Model a create or update API call as CloudFormation resource state and validate it offline before it is sent; any call that cannot be modeled exactly is skipped, never guessed (see validation-engine/API.md).
- Embeddable everywhere. Use it from the CLI, Rust, Node.js, Python, Go, or the JVM.
- Sub-second validation for typical templates.
When a template is submitted, cloudformation-validate runs a fixed pipeline:
- Parse - read JSON/YAML, resolve intrinsic functions (
Ref,Fn::GetAtt,Fn::Sub,Fn::If, …), build a reference graph with cycle detection, and model conditions with a SAT solver, producing a semantic model. - Schema validate - check each resource against the compiled CloudFormation provider schemas, producing Fatal-severity diagnostics for structural violations (type mismatches, missing required properties, invalid enums, pattern and constraint failures).
- Evaluate rules - the selected engine (Rego, CEL, or Composite) evaluates lint rules against the semantic model, producing Error/Warning/Info diagnostics for semantic issues, cross-resource references, security risks, and best practices.
- Validate Step Functions - check
AWS::StepFunctions::StateMachinedefinitions (state types,StartAt/Nextreferences, required fields). - Enrich, filter, report - attach rule descriptions and context, apply include/exclude filters and severity gating, sort by source location, deduplicate, and assemble a structured JSON report.
Use the prebuilt CLI, embed the Rust library, or install a published language binding; this source repository is not required.
| Interface | Published artifact | Install |
|---|---|---|
| CLI binary | GitHub Releases | Download the newest binary for Linux, macOS, or Windows |
| Rust library | crates.io: cloudformation-validate |
cargo add cloudformation-validate |
| Node.js | npm: @aws/cloudformation-validate |
npm install @aws/cloudformation-validate |
| Python | PyPI / TestPyPI beta | python3 -m pip install cloudformation-validate |
| Go | Go module | go get github.com/aws-cloudformation/cloudformation-validate/src/bindings-go/go@latest |
| JVM | Maven Central: software.amazon.cloudformation:cloudformation-validate |
implementation("software.amazon.cloudformation:cloudformation-validate:latest.release") |
See INSTALLATION.md for platform-specific CLI download instructions, runtime requirements, prerelease channels, version pinning, Maven syntax, and release signature verification.
# Validate a single template
cargo run -p cfn-validate -- template.yaml
# Validate every template in a directory (recurses, picks up .yaml/.yml/.json)
cargo run -p cfn-validate -- ./templates/
# Use the CEL engine instead of the default composite engine
cargo run -p cfn-validate -- template.yaml --engine cel
# Compact output for IDEs/CI
cargo run -p cfn-validate -- template.yaml --format standard
# Only report errors and above
cargo run -p cfn-validate -- template.yaml --level error
# List every available rule and exit
cargo run -p cfn-validate -- --list-rules
# Load custom Guard rules
cargo run -p cfn-validate -- template.yaml --guard-rule-source ./my-rules/Rust (bindings-rust)
Add the library facade:
[dependencies]
cloudformation-validate = "1.10.0"Construct an engine and a schema validator once, then validate many templates:
use cloudformation_validate::{
EngineConfig, RegoEngine, SchemaValidator, ValidateConfig, validate_bytes_with_path,
};
let schema_validator = SchemaValidator::default();
let engine = RegoEngine::new(EngineConfig::default())?;
let bytes = std::fs::read("template.yaml")?;
let report = validate_bytes_with_path(
&engine,
&schema_validator,
&bytes,
ValidateConfig::default(),
"template.yaml".to_string(),
)?;
for d in &report.diagnostics {
println!("[{}] {} - {}", d.severity, d.rule_id, d.message);
}The RegoEngine and CelEngine are interchangeable. For an additive setup, CompositeEngine evaluates the built-in
rules with CEL and layers your own custom rules on top through its own CompositeEngineConfig: custom CEL rules run in
the CEL engine that owns the built-ins, while custom Rego and translated Guard rules run in a separate external-only
Rego engine that is built only when such rules are supplied:
use cloudformation_validate::{CompositeEngine, CompositeEngineConfig, ExternalRuleSource};
let engine = CompositeEngine::new(
CompositeEngineConfig::new()
.with_cel_rules([ExternalRuleSource { name: "checks.json".into(), content: cel_source }])
.with_rego_rules([ExternalRuleSource { name: "checks.rego".into(), content: rego_source }])
.with_guard_rules([ExternalRuleSource { name: "policy.guard".into(), content: guard_source }]),
)?;See validation-engine/API.md for the full embedding API.
Every language binding exposes one template-validation method. Its optional per-call configuration accepts a
STANDARD or DETAILED detail level; omitting it uses DETAILED. Both levels return the same report and diagnostic
models, with enrichment fields absent at STANDARD.
Node.js (bindings-wasm)
import {RegoEngine, TemplateFile} from "@aws/cloudformation-validate";
const engine = new RegoEngine();
const report = engine.validateTemplate(new TemplateFile("template.yaml"));
for (const d of report.diagnostics) {
console.log(`[${d.severity}] ${d.ruleId}: ${d.message}`);
}
engine.free();Python (bindings-python)
from cloudformation_validate import RegoEngine
engine = RegoEngine()
report = engine.validate_template("template.yaml")
for d in report.diagnostics:
print(f"[{d.severity.name}] {d.rule_id}: {d.message}")import cfnvalidate "github.com/aws-cloudformation/cloudformation-validate/src/bindings-go/go"
engine, err := cfnvalidate.NewRegoEngine(nil)
if err != nil {
log.Fatal(err)
}
defer engine.Destroy()
report, err := engine.ValidateTemplateFile("template.yaml", nil)
for _, d := range report.Diagnostics {
fmt.Printf("[%s] %s: %s\n", d.Severity, d.RuleID, d.Message)
}JVM Java/Kotlin (bindings-jvm)
import software.amazon.cloudformation.validate.*
import java.io.File
val engine = RegoEngine()
val report = engine.validateTemplate(File("template.yaml"))
for (d in report.diagnostics) {
println("[${d.severity}] ${d.ruleId}: ${d.message}")
}Bring your own rules in any of three formats - all loadable from the CLI and the library:
- CEL (
.json) - property and data-driven checks, evaluated by the CEL engine. - Rego (
.rego) - complex cross-resource logic, evaluated by the Rego engine. - Guard DSL (
.guard) - declarative compliance rules. A supported subset of the Guard language is translated automatically and runs with either engine or the composite engine; unsupported constructs are rejected at load time rather than silently ignored.
See RULES and CUSTOM_RULES.md for the formats, available context, and examples.
This is a Cargo workspace. The main crates:
| Crate | Role |
|---|---|
| cfn-validate | cfn-validate CLI |
| validation-engine | ValidationEngine trait, orchestration pipeline, Step Functions validation |
| template-model | Template parser, intrinsic resolver, condition SAT solver, reference graph |
| rules | Rule registry, severity model, categories, and diagnostic filtering |
| diagnostics | Shared reporting types: Diagnostic, ValidationReport, metrics |
| schema-validator | JSON Schema validation against compiled CloudFormation provider schemas |
| rego-engine | Rego-based rule evaluation with custom builtins |
| cel-engine | Native Rust rules plus a CEL interpreter for custom rules |
| composite-engine | CompositeEngine - CEL evaluates the built-in rules; an optional external-only Rego engine evaluates custom Rego and Guard |
| guard-translator | Parses Guard DSL into an engine-agnostic intermediate representation |
| data-source | Build-time pipeline: downloads and processes CloudFormation schemas, generates the validation artifacts baked into the binary |
If you discover a potential security issue, please do not open a public GitHub issue. Report it privately through AWS Vulnerability Reporting instead.
Licensed under the Apache License 2.0. See NOTICE for attributions and THIRD-PARTY-LICENSES.txt for third-party license details.