DatabricksZero to Advanced

Deploy code and jobs from Git, the same way every time. This module is about the tools and the flow. The full worked project is Module 26 and 27.

  • Most of this runs on your computer or in CI, not in a notebook. Code blocks show terminal commands and config files
  • Free Edition: the docs don't say whether API access is available. Community reports say the CLI works with a personal access token (Settings → Developer) and that OAuth login did not. Treat everything here that needs the CLI as try it and see
  • Assumes you know Git and Python (Module 26 starts from there)

Check this first

In your workspace, open Settings → Developer → Access tokens. If you can create a token, you can follow topics 1–3, 5 and 8. If not, read them as reference.

15.01Hands-on on Free Edition

Databricks CLI

By the end: install the Databricks CLI and authenticate.

Install (once, on your computer):

Shell
# macOS
brew tap databricks/tap && brew install databricks
# Windows
winget install Databricks.DatabricksCLI
# Linux / WSL
curl -fsSL https://raw.githubusercontent.com/databricks/setup-cli/main/install.sh | sh

databricks -v          # shows the version

Authenticate, choose one:

Shell
databricks auth login --host https://<workspace-url>     # OAuth in the browser (recommended)
export DATABRICKS_HOST=https://<workspace-url>           # token, for scripts and CI
export DATABRICKS_TOKEN=<token>

Try it:

Shell
databricks current-user me
databricks jobs list
databricks workspace list /
databricks fs ls dbfs:/Volumes/<catalog>/dbx_course/raw
Credential Use
OAuth user login You, on your computer
OAuth with a service principal CI and automation
Personal access token Legacy. Short-lived and rotated if you must use one
  • Profiles live in ~/.databrickscfg: -p <profile> picks one
  • Order of lookup: bundle settings, environment variables, then profiles
  • The CLI wraps the REST API: every command is an API call

Free Edition login

Community posts report OAuth is not supported for this host on Free Edition. If you see it, use a personal access token.

15.02Hands-on on Free Edition

Databricks SDKs

By the end: call Databricks from Python with the SDK.

Python
# pip install databricks-sdk
from databricks.sdk import WorkspaceClient

w = WorkspaceClient()                         # uses the same auth as the CLI (env vars or profile)

for job in w.jobs.list():
    print(job.job_id, job.settings.name)

run = w.jobs.run_now(job_id=123)              # start a job
result = run.result()                         # wait for it to finish
print(result.state.result_state)
Use the When
CLI Shell scripts, CI steps, quick checks
SDK Python logic around Databricks: loops, retries, custom tooling
REST API Other languages, or calls the SDK doesn't wrap
  • WorkspaceClient() with no arguments reads the default auth chain. Don't hard-code tokens
  • The SDK is in Beta: pin a version (databricks-sdk==x.y.z)
  • The SDK has clients for jobs, clusters, tables, secrets, files, and more
  • This is what Airflow and other tools use underneath (Module 28)
15.03Hands-on on Free Edition

Databricks Declarative Automation Bundles (formerly Asset Bundles)

By the end: describe jobs and pipelines as code with a bundle.

Declarative Automation Bundles (earlier Asset Bundles) package code and resource definitions in a repo. The CLI command is still databricks bundle.

Shell
databricks bundle init            # create a project from a template
databricks bundle validate        # check the config
databricks bundle deploy -t dev   # create or update jobs, pipelines
databricks bundle run my_job -t dev
databricks bundle destroy -t dev  # remove what the bundle created
YAML
# databricks.yml
bundle:
  name: orders-etl

resources:
  jobs:
    daily_orders:
      name: daily-orders
      tasks:
        - task_key: ingest
          notebook_task:
            notebook_path: ./src/ingest.py
          environment_key: default
      environments:
        - environment_key: default
          spec:
            environment_version: "3"

targets:
  dev:
    mode: development
    default: true
  prod:
    mode: production
    workspace:
      host: https://<prod-workspace-url>
Repovalidatedeploy -t devWorkspace jobs
The repo is the source of truth. The workspace is where it runs.
  • One file, databricks.yml, with bundle, resources, targets, variables
  • Needs CLI v0.218.0 or newer
  • Targets override settings per environment. -t prod selects one
  • Resource types include jobs, pipelines, schemas, volumes, dashboards

Check the environment version

Serverless job environments are set by environment_version. Take the current value from a template made with databricks bundle init, not from this page.

15.04Hands-on on Free Edition

Git Repository Structure

By the end: lay out a Git repo that is easy to test and deploy.

databricks.yml + resources/what to deploy: jobs, pipelinessrc/<package>/code: functions and entry pointstests/unit and integration testspyproject.toml, requirements*.txtdependencies, tool settings.github/workflows/CI/CD
Rule Why
Code in a package under src/ Importable, testable, buildable as a wheel
Notebooks thin, logic in functions Testing without a cluster
resources/ split per job or pipeline Small, reviewable files
.gitignore for data, .databricks/, __pycache__, outputs Nothing sensitive in Git
One environment per target, not per branch Same code everywhere
  • Branches: main (production), short-lived feature branches, pull requests with review
  • Commit messages and pull requests say why
  • Never commit tokens, .env files or data

Same repo, any environment

A target changes where it deploys, never the code.

15.05Hands-on on Free Edition

Local Development with VS Code

By the end: develop locally in VS Code and run against Databricks.

Databricks extension for VS Code (also works in Cursor):

  • Run a local Python file on serverless compute or a cluster
  • Define, deploy and run bundles from the UI
  • Debug with Databricks Connect: your code runs locally, Spark runs in Databricks
  • Run pytest, and sync files to the workspace
Shell
pip install databricks-connect      # use the version that matches your serverless environment
Python
from databricks.connect import DatabricksSession

spark = DatabricksSession.builder.serverless().getOrCreate()
print(spark.range(5).count())
Where it runs What
Your computer Python, your IDE, tests, debugger
Databricks Spark operations and data
  • Unit tests can run locally with Spark Connect, or locally without Spark at all for pure Python
  • dbutils and display need small substitutes when running outside a notebook
  • Match the Databricks Connect version to the serverless environment version

Free Edition

Not confirmed in the docs. If it works with your token, great. If not, develop in the workspace and use Git folders (Module 26.8).

15.06Hands-on on Free Edition

Dependency and Environment Management

By the end: manage dependencies and environments reproducibly.

Layer Tool
Local virtual env python -m venv .venv, pip install -r requirements-dev.txt
Pinned versions pandas==2.2.3, not pandas
Project metadata pyproject.toml (name, version, dependencies)
Job libraries on serverless The job environment (dependencies list) or %pip install
Reusable code A built wheel (.whl) (Module 26.7)
YAML
# serverless environment in a bundle
environments:
  - environment_key: default
    spec:
      environment_version: "3"
      dependencies:
        - pandas==2.2.3
        - ./dist/*.whl
  • Serverless uses environment versions (not Databricks Runtime): pick one and test against it
  • Environments cache packages, so restarts are quicker
  • Keep dev-only tools (pytest, ruff) in a separate requirements file
  • Rebuild the wheel on each release. Never edit installed packages in place

Pin everything that runs

Unpinned dependencies are the usual reason a job breaks with no code change.

15.07Hands-on on Free Edition

Development, Test, and Production Environments

By the end: separate development, test and production.

Devyour schema or catalogschedules pausedfast changesTestCI deploys heresmall fixed dataautomated checksProdservice principal runs itonly deployed from mainpermissions locked
Way to separate Pro Con
Catalogs per environment (dev, test, prod) Clean isolation Needs more than Free Edition offers
Schemas per environment (dbx_dev, dbx_prod) Works in one catalog Weaker isolation
Workspaces per environment Strongest Costs and admin overhead
  • Pass the catalog and schema as variables (topic 11), never hard-coded
  • Development mode (bundle mode: development): resource names get a [dev <you>] prefix, schedules are paused
  • Production mode: checks that the Git branch matches, wants run_as and permissions set
  • Production data is changed only by deployed code run as a service principal, not by people

Free Edition

One workspace and no separate catalogs. Use schemas (dbx_dev, dbx_prod) to practise the pattern.

15.08Hands-on on Free Edition

GitHub Actions and Azure DevOps

By the end: run CI/CD with GitHub Actions (or Azure DevOps).

YAML
# .github/workflows/ci.yml
name: ci
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  test-and-deploy-dev:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: "3.11" }
      - run: pip install -r requirements-dev.txt
      - run: ruff check . && pytest tests/unit
      - uses: databricks/setup-cli@main
      - run: databricks bundle validate -t dev
        env:
          DATABRICKS_HOST: ${{ vars.DATABRICKS_HOST }}
          DATABRICKS_TOKEN: ${{ secrets.DATABRICKS_TOKEN }}
      - run: databricks bundle deploy -t dev
        env:
          DATABRICKS_HOST: ${{ vars.DATABRICKS_HOST }}
          DATABRICKS_TOKEN: ${{ secrets.DATABRICKS_TOKEN }}
YAML
# .github/workflows/release.yml
on:
  push:
    branches: [main]
concurrency: deploy-prod            # one deployment at a time
jobs:
  deploy-prod:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: databricks/setup-cli@main
      - run: databricks bundle deploy -t prod
        env:
          DATABRICKS_HOST: ${{ vars.DATABRICKS_HOST }}
          DATABRICKS_TOKEN: ${{ secrets.SP_TOKEN }}
Trigger Action
Pull request Lint, unit tests, deploy to dev, run checks
Push to main Deploy to prod
Tag Release deploy (topic 14)
  • Azure DevOps and GitLab use the same CLI commands in their own YAML
  • Credentials come from repository secrets. For production use a service principal, ideally with OIDC (workload identity federation) instead of a long-lived token
  • Pin the CLI action version in real projects

Never print secrets

Secrets are masked in logs only when they come from the secrets store. Don't echo them.

15.09Concept

CI/CD Pipeline Design

By the end: design a CI/CD pipeline from commit to production.

CommitBuildlint, tests, wheelDeploy testCheckintegrationDeploy prod
Each stage must pass before the next begins.
Stage Goal Fails when
Lint, format, types Style and obvious bugs Rules broken
Unit tests Logic is right A test fails
Build A versioned artifact (wheel) Build error
Deploy to test Config is valid, resources create bundle validate/deploy fails
Integration tests The job really runs on test data Job fails or outputs are wrong
Approve and deploy to prod A tagged, reviewed version ships Branch or approval rule
  • Build once, deploy the same artifact to every environment
  • Fast stages first
  • Make deployment repeatable and automatic: no manual edits in the workspace
  • Keep a manual approval before production if your team needs it
15.10Concept

Automated Tests and Quality Gates

By the end: enforce quality with automated gates.

Gate Blocks the merge when
Lint and format (ruff, black) Style rules fail
Unit tests Any test fails
Coverage threshold Coverage drops below your target
bundle validate Config is invalid
Integration tests The test job fails
Pull request review Not approved
Secret scanning A credential is committed
  • Set the gates as required checks on the main branch
  • Fast gates run on every commit. Slow ones on pull requests
  • Keep gates reliable: a flaky test that people rerun until green trains people to ignore the gate
  • Pre-commit hooks catch issues before they reach CI

A gate people trust

Few checks that always mean something beat many that nobody believes.

15.11Hands-on on Free Edition

Deployment Configuration

By the end: configure each environment with variables, targets and permissions.

YAML
variables:
  catalog:
    description: Target catalog
    default: main
  schema:
    description: Target schema

targets:
  dev:
    mode: development
    default: true
    variables:
      schema: dbx_dev
  prod:
    mode: production
    variables:
      schema: dbx_prod
    run_as:
      service_principal_name: <application-id>
    permissions:
      - group_name: data-engineers
        level: CAN_VIEW

resources:
  jobs:
    daily_orders:
      name: daily-orders
      parameters:
        - name: catalog
          default: ${var.catalog}
        - name: schema
          default: ${var.schema}
Syntax Meaning
${var.schema} A bundle variable
${bundle.target}, ${bundle.name} Current target and bundle name
${workspace.current_user.userName} The deploying user
--var="schema=x" or BUNDLE_VAR_schema Override at the command line
  • Variables resolve at deploy time. For per-run values use job parameters (Module 10.7)
  • Check the resolved config: databricks bundle validate --output json
  • Production: set run_as (a service principal) and permissions explicitly
  • Deploy production to a read-only folder so people can't edit deployed code
15.12Concept

Infrastructure as Code with Terraform

By the end: recognise where Terraform fits next to bundles.

Bundlesjobs, pipelines, dashboards, schemaswith the code that runs in themteam-owned, per projectTerraformworkspaces, metastores, groups, clusters policies, grantsplatform setupplatform-team-owned
Text
terraform {
  required_providers { databricks = { source = "databricks/databricks" } }
}
resource "databricks_job" "daily" {
  name = "daily-orders"
  # ...
}
  • Terraform describes infrastructure as code with the Databricks provider: state, plan, apply
  • Typical split: Terraform creates the platform (workspaces, catalogs, permissions, service principals). Bundles deploy each project's jobs and pipelines
  • Don't manage the same resource with both
  • Keep Terraform state in a remote backend, with locking

Not hands-on

Free Edition has no account console, so there's nothing platform-level to manage. Read this as reference.

15.13Hands-on on Free Edition

Secrets and Environment Variables

By the end: keep secrets and settings out of code.

Kind Where it lives
Secrets (tokens, passwords, keys) Databricks secret scope, CI secret store
Per-environment settings (catalog, paths) Bundle variables, job parameters
Non-secret defaults Config file in the repo
Cloud access Unity Catalog credentials, not keys in code
Shell
databricks secrets create-scope my_app
databricks secrets put-secret my_app api_key --string-value "<value>"
Python
api_key = dbutils.secrets.get(scope="my_app", key="api_key")
print(api_key)                      # shows [REDACTED]
  • Reading a secret in a notebook or job shows [REDACTED] in output. Only literal values are masked: a transformed secret can leak
  • Give each scope an ACL: grant READ to the groups or service principals that need it
  • Name scopes after an application or role, not a person
  • Environment variables (DATABRICKS_HOST, DATABRICKS_TOKEN) are for tools and CI; pull app secrets from scopes
  • Rotate secrets. Tokens should be short-lived

A committed secret is a leaked secret

Remove it from Git history and rotate it. Deleting the file in a later commit doesn't help.

15.14Hands-on on Free Edition

Release Management and Rollbacks

By the end: release with tags and roll back safely.

Shell
git tag -a v1.4.0 -m "Release 1.4.0"
git push origin v1.4.0
Merge to mainTag v1.4.0CI deploys the tagProd runs v1.4.0
A release is a tag. A rollback is deploying the previous tag.
Problem Roll back by
Bad code release Redeploy the previous tag: git checkout v1.3.2 && databricks bundle deploy -t prod
Bad config Revert the commit, redeploy
Bad data written Delta time travel and RESTORE (Module 5.10), then rerun after the fix
Failed run Repair run (Module 10.12)
  • Use semantic versions (1.4.0): breaking, feature, fix
  • Keep a short changelog
  • Rolling back code doesn't undo data it already wrote: plan for both
  • Deploy often and in small steps: small releases are easy to revert
  • Make jobs idempotent so a re-run after a rollback gives correct tables

Practise a rollback

Do one on purpose in dev. The first time shouldn't be during an incident.

Recap

What you can do now

  • CLI, SDK and bundles
  • Repo structure, local development, dependencies
  • Environments, CI/CD design and quality gates
  • Deployment config, Terraform's role, secrets
  • Releases and rollbacks