smelt explain¶
Inspect the logical and physical execution plan for a project, or the derived maintenance plan for a single incremental model.
smelt explain [MODEL_NAME] [--json] [--select <selector>] [--project-dir <path>] [--show-sql] [--period <start>..<end>]
Options¶
| Flag | Description |
|---|---|
MODEL_NAME |
Optional. Name of a single model to print the maintenance-plan report for instead of the whole-project graph. |
--json |
Output as JSON instead of human-readable text. Ignored when MODEL_NAME is given, except in combination with --show-sql. |
--select |
Select models to include (repeatable). Ignored when MODEL_NAME is given. |
--project-dir |
Path to the smelt project root. Defaults to the current directory. |
--show-sql |
With MODEL_NAME, also print the maintenance statements each cell executes. Never connects to a backend. |
--period |
With --show-sql, real literal date bounds (<start>..<end>, end exclusive) for the printed statements' region. Without it, the symbolic placeholders {{window_start}}/{{window_end}} stand in. |
Human-readable output¶
Without --json or a MODEL_NAME, smelt prints a summary of the logical graph (models, dependencies, materialization, incremental config) followed by the physical graph (planner optimisations, execution order, per-model strategy).
Per-model maintenance plan¶
smelt explain <model> prints that model's derived maintenance plan instead of the whole-project graph: every cell (trigger, corner, technique), the ledger_catch_up flag (whether the cell routes through the reconciliation ledger), the derived per-source scan clamps, each source's partition-locality verdict, any admission refusals, and the model's inbound propagation edges. This only applies to refresh: incremental models with a grain: declared — other models print a one-line notice instead.
Add --show-sql to also print, after each cell's block, the maintenance statements that cell executes — the output of the same pure emitters a run executes. Each cell's SELECT body is compiled through the real discovered project's ephemeral resolver and upstream column types, the same way a run compiles it, so the printed SQL matches what a run would compile (referenced ephemeral models are CTE-inlined, and ref-column aggregates cast to their real type). A transactional group (e.g. a paired region DELETE+INSERT) is bracketed by BEGIN/COMMIT lines. --show-sql never connects to a backend. Combine with --period <start>..<end> for the real literal window bounds, or omit it to see the symbolic {{window_start}}/{{window_end}} placeholders instead. Combined with --json, the report is emitted as JSON with a statements array per cell.
One narrow gap: a column aggregated directly off an ephemeral ref (rather than a materialized upstream model) still casts to the BIGINT default — a compile-order limitation shared identically by a real run, not an explain-specific divergence. See docs/specs/cli.md Known Divergences.
See smelt explain in the CLI reference for the full flag list and a sample maintenance-plan report.
JSON output schema¶
With --json, smelt prints a single JSON object with the following top-level fields:
{
"models": { "<model-name>": { ... }, ... },
"execution_order": ["<model-name>", ...],
"physical": { ... }
}
models — per-model entry¶
Each entry in models has:
| Field | Type | Description |
|---|---|---|
dependencies |
string[] |
Upstream model names. |
materialization |
string |
Resolved storage materialization ("view", "table", "ephemeral", "materialized_view"). |
refresh |
string |
Resolved refresh strategy: "incremental" or "materialized_view". Omitted when "full". |
incremental |
object | Present only when the model is incremental. See below. |
tags |
string[] |
Model tags from frontmatter or smelt.yml. Omitted when empty. |
owner |
string |
Model owner from frontmatter owner: key. Omitted when absent. |
origin |
object | Present only for generator-emitted models. Contains type, generator_file, generator_name. |
incremental object¶
Present on a model when refresh: incremental and grain: are set and a timeseries: block is declared.
| Field | Type | Description |
|---|---|---|
granularity |
string |
Partition granularity ("day", "week", etc.). |
partition_column |
string |
The output column used as the partition key. |
event_time_column |
string |
The source timestamp column. |
unique_key |
string[] |
Columns for MERGE-strategy deduplication. Omitted when empty. |
batch_safety |
string |
Batch-safety classification. One of "fully_batch_safe", "bounded_safe(chunk=Nd,context=Nd)", "per_partition_only". |
source_bounds |
object | Per-source bound map derived from the model's SQL. See below. Omitted when there are no timeseries upstream references. |
source_bounds field¶
The source_bounds object maps each timeseries upstream reference name to its derived bound. Lookup sources (those without a timeseries: declaration) do not appear.
Each entry is a tagged object with "type":
"bounded" — the planner derived an explicit lookback/lookahead:
{
"events_parsed": {
"type": "bounded",
"partition_col": "event_date",
"before": "PT30M",
"after": "PT0S"
}
}
| Field | Type | Description |
|---|---|---|
partition_col |
string |
The source's declared timeseries.partition_column. |
before |
string |
ISO-8601 duration — how far before the run window to read the source. "PT0S" means partition-local (no extra lookback). |
after |
string |
ISO-8601 duration — how far after the run window to read the source. |
"unbounded" — the source requires reading unbounded history (cumulative aggregation, UNBOUNDED PRECEDING):
"not_derivable" — the planner could not determine the bound (bare LAG/LEAD without a RANGE clause, or a computed-expression join without an explicit interval filter). A model with any not_derivable bound is refused at planning time.
Duration format¶
All before and after values use ISO-8601 duration strings:
| Value | Duration |
|---|---|
"PT0S" |
Zero — partition-local read. |
"PT30M" |
30 minutes. |
"PT2H" |
2 hours. |
"P1D" |
1 day. |
"P7D" |
7 days. |
physical object¶
| Field | Type | Description |
|---|---|---|
execution_order |
string[] |
Order the physical nodes are executed. |
nodes |
object | Per-node metadata. |
ephemerals |
string[] |
Logical models inlined as CTEs. |
transformations |
string[] |
Human-readable planner optimisation descriptions. |
Each node in nodes has strategy, materialization, target, and logical_origins.