BROWSE DOCS
REFERENCE
DOCS / GET STARTED

Quickstart

Take one data product from unregistered to gated: priced in CI, measured against a budget the business agreed, and visible on the board. About twenty minutes, most of it waiting for a pipeline.

Before you start

You need four things.

REQUIREMENTWHY
An IaC definitionA repository containing databricks.yml with at least one target and one job or pipeline.
Python 3.9 or laterThe CLI is a Python package.
The Databricks CLIfinowl diff and finowl guard run databricks bundle plan to read the deployed state.
A Finowl organizationAn administrator invites you by email. Sign in once at portal.finowl.cloud before you use the CLI.
NOTE
This walkthrough uses a Databricks Asset Bundle, the IaC format Finowl reads today. Terraform support is in progress — see What Finowl reads.

Set up the product

1

Install the CLI

pip install finowl
finowl --version

Four pure-Python dependencies and no compiled extensions, so it installs in seconds on a CI runner. Install it into the same environment your pipeline uses. Version pinning and pipx in Install and overview.

2

Sign in

finowl auth login

A browser opens, you authenticate with your organization's identity provider, and the CLI stores the credential in a profile. If you belong to more than one organization it asks which one to use. On a machine with no browser, use finowl auth login --no-browser for the device flow.

Confirm what you are signed in as:

$ finowl auth describe
  identity        maya@acme.com
  credential      browser login
  organization    Acme Data Platform
  host            https://api.finowl.cloud
  profile         DEFAULT
  expires         in 8 h (2026-08-20 19:40)
NOTE
CI never runs finowl auth login. A pipeline authenticates with its own OIDC identity and no stored secret — see Authentication.
3

Register the project and word its workloads

Run init from the directory holding databricks.yml, naming the target you want to describe:

finowl init --target dev

It registers the project on the platform, then walks every compute the bundle declares for that target — shared job clusters, inline task clusters, one serverless bucket per job, and each pipeline — and asks one question per compute: how much work runs on it per run?

1/3  job daily_ingest · compute main
     shared cluster 'main': Standard_DS3_v2 × 4 workers
     Workload [trivial/light/medium/heavy/intensive]: light
     ✓ light

2/3  job daily_ingest · compute serverless
     serverless bucket: 2 task(s) with no declared compute
     Workload [trivial/light/medium/heavy/intensive]: trivial
     ✓ trivial

3/3  pipeline customer_scd
     pipeline cluster: Standard_DS4_v2 × 2 workers
     Workload [trivial/light/medium/heavy/intensive]: medium
     ✓ medium

The answers land in finowl.yml next to the bundle. Commit that file — every other command reads it and none of them ever prompt.

IMPORTANT
Run init once per target. Words are never inherited between environments, because how much data a compute chews through per run is exactly what differs between dev and prod. A bundle declaring dev, staging and prod needs three runs.
4

Price it

finowl breakdown --target dev

You get a monthly projection per resource — VM cost, DBU cost and the runtime hours they were derived from — plus totals for jobs, pipelines and warehouses. This is the number the board will show, and the run is already filed against the product.

Give the product a budget

A projection with nothing to measure it against is a fact, not a control. The budget comes from the web app, not from the CLI and not from a rule.

  • Open the product on the board and run the estimator. Describe the project — volumes, pipelines, users — and it produces two figures: a P50 midpoint and a P80 that is sufficient in about 80% of modelled outcomes. If you already hold a figure from a statement of work or a spreadsheet, enter it by hand instead; it behaves identically from there.
  • Commit the estimate. That single act freezes it as the agreement, records who agreed it and when, and sets the budget. Until it happens the product is flagged as having no committed budget and no cost rule can measure anything.

Full detail in Estimate and Commit.

Write a rule and put it in force

Rules live in the web app under Rules, and a rule does nothing until a policy carries it. Create two to start:

RULESEVERITYWHAT IT CHECKS
Budget exceedingblockThe product's projected total against that product's own budget. Takes no threshold — the figure is the budget.
Max cost increase ($)warnHow much a single change adds per month. Measured against the change, not the total.

Then create a policy, add both rules to it, and target the environments it applies to. A rule in no policy never runs. The rules page marks those Never runs so an unattached rule cannot be mistaken for enforcement.

Add the gate to CI

This is the whole Finowl integration for GitHub Actions. No API key: the pipeline proves what it is with the OIDC token GitHub signs for it, so there is no secret to rotate.

The DATABRICKS_* variables are a separate credential — they authenticate the Databricks CLI to your workspace, which breakdown and guard both need. OAuth M2M is shown here; every supported method is set out in Run it in CI.

.github/workflows/finowl.yml
name: cost

on:
  pull_request:
  push:
    branches: [develop, staging, main]

env:
  FINOWL_HOST: https://api.finowl.cloud
  BUNDLE_TARGET: ${{ github.ref == 'refs/heads/main' && 'prod'
                  || github.ref == 'refs/heads/staging' && 'staging'
                  || 'dev' }}

jobs:
  cost-guard:
    runs-on: ubuntu-latest
    permissions:
      id-token: write   # without this GitHub mints no OIDC token
      contents: read
    env:
      # Databricks workspace auth — one of several methods; see "Run it in CI".
      DATABRICKS_AUTH_TYPE: oauth-m2m
      DATABRICKS_CLIENT_ID: ${{ secrets.DATABRICKS_CLIENT_ID }}
      DATABRICKS_CLIENT_SECRET: ${{ secrets.DATABRICKS_CLIENT_SECRET }}
    steps:
      - uses: actions/checkout@v4
      - uses: databricks/setup-cli@main
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - run: pip install finowl==0.2.0

      - name: Cost breakdown
        run: finowl breakdown --target "$BUNDLE_TARGET"

      - name: Cost diff
        run: finowl diff --target "$BUNDLE_TARGET"

      - name: Cost and governance guard
        run: finowl guard --target "$BUNDLE_TARGET"

Before this works, an administrator registers the pipeline once in Settings → CI connections: the repository, the issuer, and which organization its runs act for. Details in Run it in CI.

Verify the gate bites

Open a pull request that doubles a cluster. guard exits 1, the check goes red, and the failing rule names the resource and the figure. Revert it and the check goes green. That round trip is the whole product working.

What you have now

  • A registered data product with a committed budget and a full run history.
  • A projected monthly cost that updates on every pull request.
  • A CI gate that fails a merge which would break the budget.
  • A board where the product owner reads the same number the engineer saw, without anyone translating.

Next: word your other targets with finowl init --target staging, then connect an Azure subscription and a Databricks workspace so the projection sits next to what you were actually billed — see Actual cost.