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 plus your custom CEL and Guard rules, while a
separate external-only Rego engine evaluates your custom Rego 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. Available from the Rust library and every language binding (see validation-engine/API.md and the binding READMEs).
- Embeddable everywhere. Use it from the CLI, Rust, Node.js, Python, Go, or the JVM.
- Built into the AWS CDK.
aws-cdk-libvalidates every synthesized template with this library by default through itsCloudFormationValidatePlugin- no setup required. - 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 and
Guard rules run in the CEL engine that owns the built-ins, while custom Rego rules run in a separate external-only Rego
engine that is built only when Rego 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.
The template can be read from disk or passed as content already in memory - a string or raw bytes - so a template
produced by a generator, an editor buffer, or an API response is validated without touching the filesystem. In-memory
templates carry an optional name that labels the report and its diagnostics, defaulting to template: Node.js wraps
the content in TemplateContent, Python accepts bytes or a TemplateContent, the JVM offers ByteArray and
String overloads, Go takes []byte, and Rust always validates bytes.
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. Rules are evaluated by the CloudFormation Guard evaluator itself against the template as written, so every engine reports exactly whatcfn-guard validatereports; a file that does not parse is rejected at load time.
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, custom CEL, and Guard rules; an optional external-only Rego engine evaluates custom Rego |
| guard-translator | Evaluates Guard DSL with the Guard evaluator against the authored template and maps its report to findings |
| 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.