BROWSE DOCS
REFERENCE
DOCS / CLI

finowl diff

Compares what is deployed against what this branch would deploy, and reports the monthly cost difference per resource. The answer to “what does this change cost?” rather than “what does this product cost?”
finowl diff [OPTIONS]

  -b, --bundle PATH          Path to the databricks.yml bundle file.  [default: databricks.yml]
  -t, --target TEXT          Target environment to act on.  [required]
  -o, --output [table|json]  Output format.  [default: table]
  -p, --profile TEXT         Authentication profile to act as.  [env: FINOWL_CONFIG_PROFILE]

Examples

# what would this branch change about dev?
finowl diff --target dev

# the delta a release to production would make
finowl diff -t prod

# for a script
finowl diff -t prod -o json | jq '.result.total_delta'

What it needs

Unlike breakdown, this command reads the deployed state, so it needs to reach your workspace.

  • The Databricks CLI on PATH. Finowl runs databricks bundle plan --target <t> and reads the plan it produces.
  • Workspace credentials configured the way you already configure them for databricks bundle deploy. Finowl never handles them itself and never provisions, modifies or deletes anything.
  • A workload word for every compute in the bundle for this target, the same gate breakdown applies.

How the comparison is made

Both sides of the diff come from the same bundle plan — its deployed state and its planned state — and both are priced with the same workload words from finowl.yml.

NOTE
That symmetry is the point. If the two sides were timed differently, the delta would include a change of assumption alongside the change of code, and there would be no way to tell which produced the number.

Continuous pipelines are a special case: the Databricks CLI does not emit continuous: true into the plan it generates, so Finowl reads that flag back from the bundle YAML, which is authoritative for it. Without that, a continuous pipeline would be priced as if it ran on a schedule.

Reading the output

$ finowl diff --target prod

╭───────────────────────────────────────────────────╮
│ Cost Diff — Deployed vs Current                   │
│ Pricing Model: Azure Pay As You Go — Premium tier  │
╰───────────────────────────────────────────────────╯

┏━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Job / Cluster Group    ┃ Instance             ┃ Workers ┃ Monthly Hours ┃ Before (€) ┃ After (€) ┃ Δ Monthly ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━┩
│ ~ daily_ingest [light] │                      │         │               │     €44.64 │    €89.28 │  +€44.64  │
│     main               │ Standard_DS3_v2      │   4 → 8 │         37.2h │      44.64 │     89.28 │    +44.64 │
│ = customer_scd [medium]│                      │         │               │    €102.20 │   €102.20 │         — │
│     default            │ Standard_DS4_v2      │       2 │         73.0h │     102.20 │    102.20 │         — │
│ - legacy_export [light]│                      │         │               │     €22.30 │     €0.00 │  -€22.30  │
│     main               │ Standard_DS3_v2 → —  │   2 → — │          0.0h │      22.30 │      0.00 │    -22.30 │
└────────────────────────┴──────────────────────┴─────────┴───────────────┴────────────┴───────────┴───────────┘

Total monthly delta: +€22.34
COLUMNMEANING
Job / Cluster GroupThe resource and the compute inside it. One row per compute, not per resource — a job with two clusters produces two rows.
Instance / WorkersBefore and after, shown as 4 → 8 when they change. A dash on one side means the compute is being created or removed.
Monthly HoursDerived from the schedule and the workload word. Unchanged by a resize, which is why a resize shows up entirely in the cost columns.
Δ MonthlyAfter minus before. Positive adds cost, negative removes it, a dash means no movement.

When nothing changed

A branch that touches no compute produces an empty diff and a zero delta. That is a result, not an error — diff exits 0.

diff and guard

guard computes the same diff internally and then evaluates it against your rules. So why run both?

COMMANDANSWERSEXIT CODE
finowl diffWhat moved, resource by resource. Readable in a pull request without knowing any rules.0 unless it could not run
finowl guardWhether what moved is allowed here.1 on a blocking violation

In CI you generally want guard, and diff when you want the detail visible without a verdict attached. Locally, diff is the fastest way to see whether a change you are about to push is expensive.

JSON output

{
  "command": "diff",
  "target": "prod",
  "passed": true,
  "result": {
    "total_delta": 22.34,
    "diffs": [
      {
        "resource_name": "daily_ingest",
        "resource_type": "databricks_job",
        "action": "update",
        "before_total": 44.64,
        "after_total": 89.28,
        "delta": 44.64,
        "workload_before": "light",
        "workload_after": "light",
        "before_groups": [ ... ],
        "after_groups": [ ... ]
      }
    ]
  }
}

workload_before and workload_after carry the words each side was priced with. When they differ, the delta includes an assumption change and the number should be read accordingly.

Next: finowl guard, which turns this diff into a verdict.