Snapshots Tutorial#

This tutorial covers using execution snapshots for debugging, testing, and comparing solution runs.

Overview#

Snapshots capture the state of resolver execution — values, timing, status, errors, and parameters — as a JSON file. They’re useful for:

  • Debugging — Inspect what every resolver produced
  • Testing — Compare before/after to catch regressions
  • Auditing — Record what ran and what it produced
  • Sharing — Send a snapshot to a teammate for review (with redaction for secrets)
flowchart LR
  A["render<br/>solution"] --> B["Snapshot<br/>(JSON)"] --> C["show / diff<br/>commands"]

When to Use Snapshots#

Snapshots are flag-triggered (--snapshot), never automatically created. Here are the real-world scenarios where they provide value:

Use CaseScenarioHowWhy Not Just Logs?
Debugging a failed runA resolver fails or returns an unexpected value--snapshot captures full state even when execution fails — you see which resolvers succeeded, which failed, and the exact error for eachLogs show temporal events; snapshots show the complete picture — every resolver’s value, status, and timing in one structured file
Regression detectionYou changed a solution, provider config, or parameter and need to verify nothing brokeCapture a known-good baseline, then diff after changesgit diff shows YAML changes; snapshot diff shows what those changes did to the output
Environment comparisonYou need to see exactly which resolver values differ between staging and productionSnapshot with -r env=staging vs -r env=production and diffEnvironment differences are computed at runtime by providers — they can’t be seen by inspecting the solution YAML
Golden-file testingAutomated CI checks that resolver outputs haven’t driftedThe soltesting package compares execution output against stored snapshots, normalizing timestamps and UUIDsManual inspection doesn’t scale; golden files catch regressions automatically
Audit trailRecord what values were resolved at a specific point in time (before/after a deployment or config change)Capture and archive snapshots with timestampsLogs are ephemeral; snapshots are portable JSON files you can store and revisit
Safe sharingA teammate needs to see your resolver output, but the solution uses secrets or credentials--redact replaces values of sensitive: true resolvers with <redacted>Copy-pasting terminal output risks leaking secrets and loses structure

Key Properties#

  • Captures failures too — Unlike normal output that stops on error, snapshots record partial state. A snapshot from a failed run shows you exactly which resolvers succeeded before the failure.
  • Structured data — Every resolver’s value, status, duration, phase, provider calls, and errors in one JSON file. Supports programmatic processing (-o json), CI pipeline assertions, and diff operations.
  • Redaction-safe — Resolvers marked sensitive: true in the solution YAML have their values replaced with <redacted> when using --redact, making snapshots safe to share or store in version control.
  • Deterministic diffsnapshot diff with --ignore-fields duration,providerCalls strips non-deterministic timing data, leaving only meaningful value and status changes.

Creating Snapshots#

From render#

Snapshots are created with scafctl render solution:

# Render and save snapshot
scafctl render solution -f my-solution.yaml \
  --snapshot --snapshot-file=snapshot.json
# Render and save snapshot
scafctl render solution -f my-solution.yaml `
  --snapshot --snapshot-file=snapshot.json

From run resolver#

You can also capture snapshots when running resolvers only (without actions):

scafctl run resolver -f my-solution.yaml \
  --snapshot --snapshot-file=snapshot.json
scafctl run resolver -f my-solution.yaml `
  --snapshot --snapshot-file=snapshot.json

This is useful when you want to inspect resolver execution without triggering actions.

From snapshot save#

Or use the dedicated save command:

scafctl snapshot save -f my-solution.yaml --output snapshot.json
scafctl snapshot save -f my-solution.yaml --output snapshot.json

With Parameters#

scafctl render solution -f my-solution.yaml \
  -r env=production \
  --snapshot --snapshot-file=prod-snapshot.json
scafctl render solution -f my-solution.yaml `
  -r env=production `
  --snapshot --snapshot-file=prod-snapshot.json

With Redaction#

Redact sensitive values (resolvers marked sensitive: true):

scafctl render solution -f my-solution.yaml \
  --snapshot --snapshot-file=safe-snapshot.json --redact
scafctl render solution -f my-solution.yaml `
  --snapshot --snapshot-file=safe-snapshot.json --redact

Viewing Snapshots#

Summary View (Default)#

scafctl snapshot show snapshot.json
scafctl snapshot show snapshot.json

Output:

Snapshot Summary

Solution:   my-app
Version:    1.0.0
Created:    2026-02-09T10:30:00Z
Duration:   145ms
Status:     success

Resolvers: 8 total
  ✅ Succeeded: 7
  ❌ Failed:    0
  ⏭  Skipped:   1

Parameters:
  env = production

Resolver Details#

scafctl snapshot show snapshot.json --format resolvers
scafctl snapshot show snapshot.json --format resolvers

Shows each resolver’s name, status, value, duration, and provider calls.

JSON Output#

scafctl snapshot show snapshot.json --format json
scafctl snapshot show snapshot.json --format json

Full snapshot data for programmatic processing.

Verbose Mode#

scafctl snapshot show snapshot.json --verbose
scafctl snapshot show snapshot.json --verbose

Includes additional details like individual provider call timing.

Comparing Snapshots#

Basic Diff#

scafctl snapshot diff before.json after.json
scafctl snapshot diff before.json after.json

Output:

Snapshot Diff

Total: 8 resolvers
  Added:     1
  Removed:   0
  Modified:  2
  Unchanged: 5

Modified Resolvers:
  replicas: 2 → 5
  log_level: "debug" → "warn"

Added Resolvers:
  + cdn_endpoint: "cdn.prod.example.com"

Ignore Timing#

Filter out non-deterministic fields:

scafctl snapshot diff before.json after.json \
  --ignore-fields duration,providerCalls
scafctl snapshot diff before.json after.json `
  --ignore-fields duration,providerCalls

Show Only Changes#

scafctl snapshot diff before.json after.json --ignore-unchanged
scafctl snapshot diff before.json after.json --ignore-unchanged

Output Formats#

# Human-readable (default)
scafctl snapshot diff before.json after.json --format human

# JSON for CI pipelines
scafctl snapshot diff before.json after.json --format json

# Unified diff format
scafctl snapshot diff before.json after.json --format unified

# Save diff to file
scafctl snapshot diff before.json after.json --output diff-report.json --format json
# Human-readable (default)
scafctl snapshot diff before.json after.json --format human

# JSON for CI pipelines
scafctl snapshot diff before.json after.json --format json

# Unified diff format
scafctl snapshot diff before.json after.json --format unified

# Save diff to file
scafctl snapshot diff before.json after.json --output diff-report.json --format json

Common Workflows#

Debugging a Failure#

# 1. Capture the failing state
scafctl snapshot save -f broken-solution.yaml --output failing.json

# 2. Inspect what went wrong
scafctl snapshot show failing.json --format resolvers --verbose

# 3. Fix the issue and re-capture
scafctl snapshot save -f fixed-solution.yaml --output fixed.json

# 4. Verify the fix
scafctl snapshot diff failing.json fixed.json
# 1. Capture the failing state
scafctl snapshot save -f broken-solution.yaml --output failing.json

# 2. Inspect what went wrong
scafctl snapshot show failing.json --format resolvers --verbose

# 3. Fix the issue and re-capture
scafctl snapshot save -f fixed-solution.yaml --output fixed.json

# 4. Verify the fix
scafctl snapshot diff failing.json fixed.json

Regression Testing#

# 1. Capture baseline
scafctl snapshot save -f solution.yaml --output baseline.json \
  --ignore-fields duration

# 2. Make changes to the solution
# ...

# 3. Capture new state
scafctl snapshot save -f solution.yaml --output current.json

# 4. Compare (ignore timing differences)
scafctl snapshot diff baseline.json current.json \
  --ignore-fields duration,providerCalls --format json

# 5. Use exit code in CI
if ! scafctl snapshot diff baseline.json current.json \
  --ignore-fields duration,providerCalls --ignore-unchanged; then
  echo "Snapshot regression detected!"
  exit 1
fi
# 1. Capture baseline
scafctl snapshot save -f solution.yaml --output baseline.json `
  --ignore-fields duration

# 2. Make changes to the solution
# ...

# 3. Capture new state
scafctl snapshot save -f solution.yaml --output current.json

# 4. Compare (ignore timing differences)
scafctl snapshot diff baseline.json current.json `
  --ignore-fields duration,providerCalls --format json

# 5. Use exit code in CI
scafctl snapshot diff baseline.json current.json `
  --ignore-fields duration,providerCalls --ignore-unchanged
if ($LASTEXITCODE -ne 0) {
  Write-Output "Snapshot regression detected!"
  exit 1
}

Environment Comparison#

# Capture staging
scafctl render solution -f solution.yaml -r env=staging \
  --snapshot --snapshot-file=staging.json

# Capture production
scafctl render solution -f solution.yaml -r env=production \
  --snapshot --snapshot-file=production.json

# Compare configurations
scafctl snapshot diff staging.json production.json --ignore-unchanged
# Capture staging
scafctl render solution -f solution.yaml -r env=staging `
  --snapshot --snapshot-file=staging.json

# Capture production
scafctl render solution -f solution.yaml -r env=production `
  --snapshot --snapshot-file=production.json

# Compare configurations
scafctl snapshot diff staging.json production.json --ignore-unchanged

Safe Sharing#

# Redact secrets before sharing
scafctl snapshot save -f solution.yaml --output shareable.json --redact
# Redact secrets before sharing
scafctl snapshot save -f solution.yaml --output shareable.json --redact

Examples#

ExampleDescriptionRun
basic-snapshot.yamlBasic snapshot capturescafctl render solution -f examples/snapshots/basic-snapshot.yaml --snapshot --snapshot-file=/tmp/snapshot.json
snapshot-diff.yamlComparing snapshots across environmentsSee example header for full commands
redacted-snapshot.yamlRedacting sensitive datascafctl render solution -f examples/snapshots/redacted-snapshot.yaml --snapshot --snapshot-file=/tmp/redacted.json --redact

Snapshot Command Reference#

CommandDescription
scafctl snapshot show <file>Display a saved snapshot
scafctl snapshot diff <a> <b>Compare two snapshots
scafctl snapshot save -f <solution>Run resolvers and save snapshot
scafctl render solution --snapshotCreate snapshot during render

Flags#

FlagCommandsDescription
--formatshow, diffOutput format (summary/json/resolvers/human/unified)
--verboseshowInclude additional detail
--ignore-unchangeddiffOnly show differences
--ignore-fieldsdiffComma-separated fields to ignore
--outputsave, diffOutput file path
--redactsave, renderRedact sensitive resolver values
-r key=valuesavePass resolver parameters (also supports @file.yaml and @- for stdin)

Using Snapshots with the MCP Server#

When using AI agents (VS Code Copilot, Claude, Cursor), the MCP server provides snapshot tools:

  • show_snapshot — Display snapshot contents with structured output (same as scafctl snapshot show)
  • diff_snapshots — Compare two snapshots and return structured diffs showing added, removed, modified, and unchanged resolvers

The analyze_execution prompt automatically suggests using snapshots for debugging.

Next Steps#