CloudBurn supports two output formats: table for human-readable terminal output and json for machine-readable structured data.
table (default)
The table format renders findings as bordered ASCII tables. CloudBurn automatically adjusts column widths to fit your terminal and hides columns that have no data for the current scan, so the exact layout varies by run and terminal size.
Example output from an IaC scan:
+----------+------------------+----------+--------+---------+---------------------+-------------------------+------+--------+----------------------------------------------------+
| Provider | RuleId | Severity | Source | Service | ResourceId | Path | Line | Column | Message |
+----------+------------------+----------+--------+---------+---------------------+-------------------------+------+--------+----------------------------------------------------+
| aws | CLDBRN-AWS-EBS-1 | medium | iac | ebs | aws_ebs_volume.main | modules/storage/main.tf | 12 | 1 | EBS volumes should use current-generation storage. |
+----------+------------------+----------+--------+---------+---------------------+-------------------------+------+--------+----------------------------------------------------+
The same rule on a live discovery run fills in the resource columns instead of the file columns:
+----------+------------------+----------+-----------+---------+--------------+-----------------------+--------------+--------------+----------------------------------------------------+
| Provider | RuleId | Severity | Source | Service | ResourceType | ResourceId | AccountId | Region | Message |
+----------+------------------+----------+-----------+---------+--------------+-----------------------+--------------+--------------+----------------------------------------------------+
| aws | CLDBRN-AWS-EBS-1 | medium | discovery | ebs | ec2:volume | vol-0abc123def456789a | 123456789012 | eu-central-1 | EBS volumes should use current-generation storage. |
+----------+------------------+----------+-----------+---------+--------------+-----------------------+--------------+--------------+----------------------------------------------------+
Finding columns
CloudBurn renders these columns in this order and drops any that are empty for every finding in the run:
| Column | Description |
|---|---|
| Provider | Cloud provider (aws) |
| RuleId | Rule that produced the finding |
| Severity | Relative cost impact: high, medium, or low |
| Source | Scan mode that produced the finding: iac or discovery |
| Service | AWS service the rule targets |
| ResourceType | AWS resource type, on discovery findings that carry one |
| ResourceId | Terraform address or CloudFormation logical ID for IaC, live resource ID for discovery |
| Action | The exact operation an AWS Cost Optimization Hub recommendation proposes, such as Stop |
| AccountId | AWS account the resource belongs to (discovery) |
| Region | AWS region the resource is in (discovery) |
| Path | File path where the resource is defined (IaC) |
| Line | Line number in the file (IaC) |
| Column | Column number in the file (IaC) |
| Message | What CloudBurn found and why it matters |
The Action column appears for the opt-in Cost Optimization Hub rules. CloudBurn reports the operation AWS recommends; it never runs it. Review the action and its rollback path before acting on it.
When there are no active findings, CloudBurn prints a confirmation message instead of an empty table: No findings., or No active findings. when every finding was suppressed.
Diagnostics and suppressed findings
Non-fatal scan diagnostics (such as an access-denied API call during discovery) render as a separate Diagnostics table below the findings table, with Status, RuleId, and Region columns instead of resource-level columns:
Diagnostics
+----------+---------------+------------------+-----------+---------+--------------+----------------------------------------------+
| Provider | Status | RuleId | Source | Service | Region | Message |
+----------+---------------+------------------+-----------+---------+--------------+----------------------------------------------+
| aws | access_denied | CLDBRN-AWS-EC2-1 | discovery | ec2 | eu-central-1 | Access denied calling ec2:DescribeInstances. |
+----------+---------------+------------------+-----------+---------+--------------+----------------------------------------------+
Findings suppressed by an inline cloudburn-ignore comment (see cloudburn scan) are excluded from the findings table and instead reported as a trailing Suppressed: <count> line. Suppressed findings never affect --exit-code or --fail-on.
Evidence freshness
cloudburn discover collects evidence through the evidence cache, so table output ends with a freshness summary telling you how much of the run came from the cache and how old the oldest observation is:
Evidence: 6 cached, 12 collected; 1 incomplete.
Oldest observation: 2026-02-04T09:12:31.004Z
cached counts artifacts reused from the cache and collected counts artifacts loaded from AWS on this run. incomplete counts artifacts whose collection did not cover everything the rules asked for; those never enter the cache and their gaps show up as diagnostics. The summary is absent for IaC scans, which collect no evidence.
json
The json format outputs a structured JSON object to stdout. Use this for scripting, CI annotation systems, or feeding results into other tools.
Example output:
{
"providers": [
{
"provider": "aws",
"rules": [
{
"ruleId": "CLDBRN-AWS-EBS-1",
"service": "ebs",
"severity": "medium",
"source": "iac",
"message": "EBS volumes should use current-generation storage.",
"findings": [
{
"resourceId": "aws_ebs_volume.main",
"location": {
"path": "modules/storage/main.tf",
"line": 12,
"column": 1
}
}
]
}
]
}
]
}
The serialized result is the SDK's ScanResult object, so a run can also carry diagnostics, suppressed, policy, evaluations, and evidence keys. Discovery runs keep the full evidence provenance that table output summarizes:
{
"providers": [],
"evidence": [
{
"datasetKey": "aws-ebs-volumes",
"region": "eu-central-1",
"source": "cache",
"collectedAt": "2026-02-04T09:12:31.004Z",
"observedAt": "2026-02-04T09:12:31.004Z",
"complete": true,
"cacheStatus": "hit"
}
]
}
source is live or cache. cacheStatus records why the entry was or was not reused: hit, miss, stale, corrupt, obsolete, refresh, or off. Entries can also carry observationWindow, coverage, and their own diagnostics. See Evidence cache for the cache modes and ScanResult for the full type.
Selecting a format
Pass --format as a global flag (before the subcommand):
cloudburn --format json scan ./iac
cloudburn --format json discover
Format precedence
--format flag > config file > table (default)
Setting a default in your config file
You can set a default format per scan type in .cloudburn.yml:
iac:
format: json
discovery:
format: table
See Configuration for the full config reference.
Piping JSON to jq
Extract only the finding messages:
cloudburn --format json scan ./iac | jq '.providers[].rules[].message'
Count total findings:
cloudburn --format json scan ./iac | jq '[.providers[].rules[].findings[]] | length'
Extract findings for a specific service:
cloudburn --format json scan ./iac | jq '.providers[].rules[] | select(.service == "ebs")'
What's next
| CI/CD Integration | Use JSON output in CI annotation workflows |
| Exit Codes | Combine JSON output with exit codes |
| Configuration | Set a default format in your config file |