<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic One Bundle, Three Environments: CICD for Databricks with Declarative Automation Bundles in Community Articles</title>
    <link>https://community.databricks.com/t5/community-articles/one-bundle-three-environments-cicd-for-databricks-with/m-p/175983#M1894</link>
    <description>&lt;P&gt;&lt;STRONG&gt;DevOps · CICD · Deploy the same definition to dev, staging and prod, and never edit a job in the UI again&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;By&amp;nbsp;&lt;a href="https://community.databricks.com/t5/user/viewprofilepage/user-id/121740"&gt;@SrinuB&lt;/a&gt;&amp;nbsp; in collaboration with&amp;nbsp;&lt;a href="https://community.databricks.com/t5/user/viewprofilepage/user-id/85833"&gt;@sridharplv&lt;/a&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Somebody "just fixed" a production job in the UI on Friday evening. By Monday it no longer matches the repo, nobody remembers what changed, and the dev copy behaves differently from prod.&lt;/P&gt;&lt;P&gt;This is configuration drift, and it is the problem CICD exists to remove. On Databricks the recommended way to do it is Declarative Automation Bundles (formerly Databricks Asset Bundles, DABs). The docs state that bundles are the recommended approach to CICD on Databricks.&lt;/P&gt;&lt;H2&gt;What a bundle is&lt;/H2&gt;&lt;P&gt;A bundle describes your jobs, Lakeflow pipelines and other resources as source files, next to your code, in Git. The CLI validates the definition and deploys it to a workspace. The same files go to every environment. Only the &lt;EM&gt;target&lt;/EM&gt; changes.&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="blog5_dab_cicd.png" style="width: 799px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/33156iA4BD5AABE5128B5A/image-size/large?v=v2&amp;amp;px=999" role="button" title="blog5_dab_cicd.png" alt="blog5_dab_cicd.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;H2&gt;One file, three targets&lt;/H2&gt;&lt;PRE&gt;bundle:
  name: customer_pipeline

include:
  - resources/*.yml

targets:
  dev:
    mode: development
    default: true
    workspace:
      host: &amp;lt;dev-workspace-url&amp;gt;

  staging:
    workspace:
      host: &amp;lt;staging-workspace-url&amp;gt;

  prod:
    mode: production
    workspace:
      host: &amp;lt;prod-workspace-url&amp;gt;
    run_as:
      service_principal_name: &amp;lt;service-principal-application-id&amp;gt;&lt;/PRE&gt;&lt;P&gt;The jobs themselves live in resources/ and are shared by all three targets. Per-environment values (catalog names, cluster sizes, schedules) are overrides on the target, not copies of the job.&lt;/P&gt;&lt;H2&gt;What the two modes do for you&lt;/H2&gt;&lt;P&gt;From the docs, &lt;STRONG&gt;development mode&lt;/STRONG&gt;:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Prefixes deployed resources with [dev &amp;lt;your short name&amp;gt;], so developers do not collide&lt;/LI&gt;&lt;LI&gt;Tags jobs and pipelines with dev&lt;/LI&gt;&lt;LI&gt;Pauses all schedules and triggers&lt;/LI&gt;&lt;LI&gt;Enables concurrent runs on jobs&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;&lt;STRONG&gt;Production mode&lt;/STRONG&gt; adds guard rails instead:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Deployment fails validation unless Lakeflow pipelines are development: false&lt;/LI&gt;&lt;LI&gt;If the target sets git.branch, the current branch must match it&lt;/LI&gt;&lt;LI&gt;Cluster overrides on deploy are not allowed&lt;/LI&gt;&lt;LI&gt;run_as should be a service principal, which the docs recommend&lt;/LI&gt;&lt;/UL&gt;&lt;H2&gt;The pipeline, step by step&lt;/H2&gt;&lt;OL&gt;&lt;LI&gt;&lt;STRONG&gt;Pull request:&lt;/STRONG&gt; lint, run unit tests with pytest, then databricks bundle validate. Block the merge if anything fails.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Merge to main:&lt;/STRONG&gt; databricks bundle deploy -t staging, then databricks bundle run -t staging &amp;lt;test_job&amp;gt;. A failed smoke test stops the release.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Approval, then prod:&lt;/STRONG&gt; a manual gate (GitHub environment protection or an Azure DevOps approval), then databricks bundle deploy -t prod.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Monitor:&lt;/STRONG&gt; alerts on job failure. To roll back, redeploy the previous Git tag.&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;The docs list Azure DevOps, GitHub Actions and Jenkins as the usual orchestrators. The bundle does not care which one you pick.&lt;/P&gt;&lt;H2&gt;Authentication: no personal tokens&lt;/H2&gt;&lt;P&gt;The docs say to use service principals, not users, for CICD. For the credential, the recommended option is &lt;STRONG&gt;workload identity federation&lt;/STRONG&gt;, which removes the need to store a Databricks secret at all. In GitHub Actions that means id-token: write permissions plus these environment variables:&lt;/P&gt;&lt;PRE&gt;permissions:
  id-token: write
  contents: read

steps:
  - uses: actions/checkout@v4
  - uses: databricks/setup-cli@main
  - run: databricks bundle deploy -t prod
    env:
      DATABRICKS_AUTH_TYPE: github-oidc
      DATABRICKS_HOST: &amp;lt;prod-workspace-url&amp;gt;
      DATABRICKS_CLIENT_ID: &amp;lt;service-principal-application-id&amp;gt;&lt;/PRE&gt;&lt;P&gt;You create a federation policy on the service principal whose subject matches the GitHub token subject. A client-secret token stored as a GitHub secret also works, but it is the second choice.&lt;/P&gt;&lt;H2&gt;What to watch out for&lt;/H2&gt;&lt;UL&gt;&lt;LI&gt;&lt;STRONG&gt;Bundle identity is name, target and deployer.&lt;/STRONG&gt; Two bundles sharing all three overwrite each other's deployments.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;bundle destroy is permanent.&lt;/STRONG&gt; It deletes the deployed jobs, pipelines and artifacts. Use --auto-approve only in throwaway dev targets.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Prod stays read-only.&lt;/STRONG&gt; The docs recommend deploying to a read-only folder so non-admins cannot change deployed assets.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Unit tests are not enough.&lt;/STRONG&gt; Opinion: the staging run on realistic data is the step that catches real failures. Keep it.&lt;/LI&gt;&lt;/UL&gt;&lt;H2&gt;A 20-minute check you can run this week&lt;/H2&gt;&lt;OL&gt;&lt;LI&gt;Pick one job that was created in the UI&lt;/LI&gt;&lt;LI&gt;Run databricks bundle init and recreate it as a resource file&lt;/LI&gt;&lt;LI&gt;Deploy it to a dev target and compare the run with the original&lt;/LI&gt;&lt;LI&gt;Add databricks bundle validate to a pull request check&lt;/LI&gt;&lt;/OL&gt;&lt;H2&gt;The takeaway&lt;/H2&gt;&lt;OL&gt;&lt;LI&gt;&lt;STRONG&gt;Everything is code.&lt;/STRONG&gt; Jobs and pipelines live in Git and go through review.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;One definition, many targets.&lt;/STRONG&gt; Environments differ by overrides, not by copies.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Use a service principal&lt;/STRONG&gt;, ideally with workload identity federation.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Gate production.&lt;/STRONG&gt; Validate in the pull request, test in staging, approve, then deploy.&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;Which job in your workspace would you move into a bundle first?&lt;/P&gt;&lt;H2&gt;References&lt;/H2&gt;&lt;UL&gt;&lt;LI&gt;Declarative Automation Bundles, Databricks documentation&lt;/LI&gt;&lt;LI&gt;Bundle deployment modes, Databricks documentation&lt;/LI&gt;&lt;LI&gt;CI/CD on Databricks, Databricks documentation&lt;/LI&gt;&lt;LI&gt;GitHub Actions for Databricks, Databricks documentation&lt;/LI&gt;&lt;/UL&gt;</description>
    <pubDate>Mon, 09 Nov 2026 14:40:41 GMT</pubDate>
    <dc:creator>SrinuB</dc:creator>
    <dc:date>2026-11-09T14:40:41Z</dc:date>
    <item>
      <title>One Bundle, Three Environments: CICD for Databricks with Declarative Automation Bundles</title>
      <link>https://community.databricks.com/t5/community-articles/one-bundle-three-environments-cicd-for-databricks-with/m-p/175983#M1894</link>
      <description>&lt;P&gt;&lt;STRONG&gt;DevOps · CICD · Deploy the same definition to dev, staging and prod, and never edit a job in the UI again&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;By&amp;nbsp;&lt;a href="https://community.databricks.com/t5/user/viewprofilepage/user-id/121740"&gt;@SrinuB&lt;/a&gt;&amp;nbsp; in collaboration with&amp;nbsp;&lt;a href="https://community.databricks.com/t5/user/viewprofilepage/user-id/85833"&gt;@sridharplv&lt;/a&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Somebody "just fixed" a production job in the UI on Friday evening. By Monday it no longer matches the repo, nobody remembers what changed, and the dev copy behaves differently from prod.&lt;/P&gt;&lt;P&gt;This is configuration drift, and it is the problem CICD exists to remove. On Databricks the recommended way to do it is Declarative Automation Bundles (formerly Databricks Asset Bundles, DABs). The docs state that bundles are the recommended approach to CICD on Databricks.&lt;/P&gt;&lt;H2&gt;What a bundle is&lt;/H2&gt;&lt;P&gt;A bundle describes your jobs, Lakeflow pipelines and other resources as source files, next to your code, in Git. The CLI validates the definition and deploys it to a workspace. The same files go to every environment. Only the &lt;EM&gt;target&lt;/EM&gt; changes.&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="blog5_dab_cicd.png" style="width: 799px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/33156iA4BD5AABE5128B5A/image-size/large?v=v2&amp;amp;px=999" role="button" title="blog5_dab_cicd.png" alt="blog5_dab_cicd.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;H2&gt;One file, three targets&lt;/H2&gt;&lt;PRE&gt;bundle:
  name: customer_pipeline

include:
  - resources/*.yml

targets:
  dev:
    mode: development
    default: true
    workspace:
      host: &amp;lt;dev-workspace-url&amp;gt;

  staging:
    workspace:
      host: &amp;lt;staging-workspace-url&amp;gt;

  prod:
    mode: production
    workspace:
      host: &amp;lt;prod-workspace-url&amp;gt;
    run_as:
      service_principal_name: &amp;lt;service-principal-application-id&amp;gt;&lt;/PRE&gt;&lt;P&gt;The jobs themselves live in resources/ and are shared by all three targets. Per-environment values (catalog names, cluster sizes, schedules) are overrides on the target, not copies of the job.&lt;/P&gt;&lt;H2&gt;What the two modes do for you&lt;/H2&gt;&lt;P&gt;From the docs, &lt;STRONG&gt;development mode&lt;/STRONG&gt;:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Prefixes deployed resources with [dev &amp;lt;your short name&amp;gt;], so developers do not collide&lt;/LI&gt;&lt;LI&gt;Tags jobs and pipelines with dev&lt;/LI&gt;&lt;LI&gt;Pauses all schedules and triggers&lt;/LI&gt;&lt;LI&gt;Enables concurrent runs on jobs&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;&lt;STRONG&gt;Production mode&lt;/STRONG&gt; adds guard rails instead:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Deployment fails validation unless Lakeflow pipelines are development: false&lt;/LI&gt;&lt;LI&gt;If the target sets git.branch, the current branch must match it&lt;/LI&gt;&lt;LI&gt;Cluster overrides on deploy are not allowed&lt;/LI&gt;&lt;LI&gt;run_as should be a service principal, which the docs recommend&lt;/LI&gt;&lt;/UL&gt;&lt;H2&gt;The pipeline, step by step&lt;/H2&gt;&lt;OL&gt;&lt;LI&gt;&lt;STRONG&gt;Pull request:&lt;/STRONG&gt; lint, run unit tests with pytest, then databricks bundle validate. Block the merge if anything fails.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Merge to main:&lt;/STRONG&gt; databricks bundle deploy -t staging, then databricks bundle run -t staging &amp;lt;test_job&amp;gt;. A failed smoke test stops the release.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Approval, then prod:&lt;/STRONG&gt; a manual gate (GitHub environment protection or an Azure DevOps approval), then databricks bundle deploy -t prod.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Monitor:&lt;/STRONG&gt; alerts on job failure. To roll back, redeploy the previous Git tag.&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;The docs list Azure DevOps, GitHub Actions and Jenkins as the usual orchestrators. The bundle does not care which one you pick.&lt;/P&gt;&lt;H2&gt;Authentication: no personal tokens&lt;/H2&gt;&lt;P&gt;The docs say to use service principals, not users, for CICD. For the credential, the recommended option is &lt;STRONG&gt;workload identity federation&lt;/STRONG&gt;, which removes the need to store a Databricks secret at all. In GitHub Actions that means id-token: write permissions plus these environment variables:&lt;/P&gt;&lt;PRE&gt;permissions:
  id-token: write
  contents: read

steps:
  - uses: actions/checkout@v4
  - uses: databricks/setup-cli@main
  - run: databricks bundle deploy -t prod
    env:
      DATABRICKS_AUTH_TYPE: github-oidc
      DATABRICKS_HOST: &amp;lt;prod-workspace-url&amp;gt;
      DATABRICKS_CLIENT_ID: &amp;lt;service-principal-application-id&amp;gt;&lt;/PRE&gt;&lt;P&gt;You create a federation policy on the service principal whose subject matches the GitHub token subject. A client-secret token stored as a GitHub secret also works, but it is the second choice.&lt;/P&gt;&lt;H2&gt;What to watch out for&lt;/H2&gt;&lt;UL&gt;&lt;LI&gt;&lt;STRONG&gt;Bundle identity is name, target and deployer.&lt;/STRONG&gt; Two bundles sharing all three overwrite each other's deployments.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;bundle destroy is permanent.&lt;/STRONG&gt; It deletes the deployed jobs, pipelines and artifacts. Use --auto-approve only in throwaway dev targets.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Prod stays read-only.&lt;/STRONG&gt; The docs recommend deploying to a read-only folder so non-admins cannot change deployed assets.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Unit tests are not enough.&lt;/STRONG&gt; Opinion: the staging run on realistic data is the step that catches real failures. Keep it.&lt;/LI&gt;&lt;/UL&gt;&lt;H2&gt;A 20-minute check you can run this week&lt;/H2&gt;&lt;OL&gt;&lt;LI&gt;Pick one job that was created in the UI&lt;/LI&gt;&lt;LI&gt;Run databricks bundle init and recreate it as a resource file&lt;/LI&gt;&lt;LI&gt;Deploy it to a dev target and compare the run with the original&lt;/LI&gt;&lt;LI&gt;Add databricks bundle validate to a pull request check&lt;/LI&gt;&lt;/OL&gt;&lt;H2&gt;The takeaway&lt;/H2&gt;&lt;OL&gt;&lt;LI&gt;&lt;STRONG&gt;Everything is code.&lt;/STRONG&gt; Jobs and pipelines live in Git and go through review.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;One definition, many targets.&lt;/STRONG&gt; Environments differ by overrides, not by copies.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Use a service principal&lt;/STRONG&gt;, ideally with workload identity federation.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Gate production.&lt;/STRONG&gt; Validate in the pull request, test in staging, approve, then deploy.&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;Which job in your workspace would you move into a bundle first?&lt;/P&gt;&lt;H2&gt;References&lt;/H2&gt;&lt;UL&gt;&lt;LI&gt;Declarative Automation Bundles, Databricks documentation&lt;/LI&gt;&lt;LI&gt;Bundle deployment modes, Databricks documentation&lt;/LI&gt;&lt;LI&gt;CI/CD on Databricks, Databricks documentation&lt;/LI&gt;&lt;LI&gt;GitHub Actions for Databricks, Databricks documentation&lt;/LI&gt;&lt;/UL&gt;</description>
      <pubDate>Mon, 09 Nov 2026 14:40:41 GMT</pubDate>
      <guid>https://community.databricks.com/t5/community-articles/one-bundle-three-environments-cicd-for-databricks-with/m-p/175983#M1894</guid>
      <dc:creator>SrinuB</dc:creator>
      <dc:date>2026-11-09T14:40:41Z</dc:date>
    </item>
  </channel>
</rss>

