<?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>article DABs Migration Guide: Terraform to the Direct Deployment Engine in Technical Blog</title>
    <link>https://community.databricks.com/t5/technical-blog/dabs-migration-guide-terraform-to-the-direct-deployment-engine/ba-p/165694</link>
    <description>&lt;P&gt;This guide covers the migration procedure and several behaviors worth knowing that this migration surfaced in practice.&lt;/P&gt;
&lt;H3&gt;Background and timeline&lt;/H3&gt;
&lt;P&gt;The deployment backend for DABs is moving from the &lt;STRONG&gt;Terraform engine&lt;/STRONG&gt; to the new &lt;STRONG&gt;direct deployment engine&lt;/STRONG&gt;. The direct engine talks to the Databricks REST APIs directly. It no longer uses the Terraform provider or a &lt;SPAN&gt;terraform.tfstate&lt;/SPAN&gt; file, which removes a common source of state-related deployment failures and makes deployments simpler and faster.&lt;/P&gt;
&lt;P&gt;The transition is already in progress:&lt;/P&gt;
&lt;TABLE&gt;
&lt;THEAD&gt;
&lt;TR&gt;
&lt;TH&gt;Date&lt;/TH&gt;
&lt;TH&gt;Change&lt;/TH&gt;
&lt;/TR&gt;
&lt;/THEAD&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;Jun 10, 2026 (CLI 1.3.0)&lt;/TD&gt;
&lt;TD&gt;Direct engine becomes the default for new bundles. Existing Terraform bundles keep their engine until migrated.&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;Jul 24, 2026 - Aug 11, 2026&lt;/TD&gt;
&lt;TD&gt;Direct engine becomes the default for all bundles deployed in DABs-in-the-Workspace. Bundles still on Terraform are auto-migrated.&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;Aug 26, 2026&lt;/TD&gt;
&lt;TD&gt;Terraform deployments will be auto-migrated for CLI v 1.14.0 or later.&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;Sep 2026&lt;/TD&gt;
&lt;TD&gt;Terraform engine is disabled in new CLI releases.&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;Later&lt;/TD&gt;
&lt;TD&gt;The Terraform engine is removed entirely.&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;P&gt;Sources: &lt;A href="https://docs.databricks.com/aws/en/release-notes/whats-coming" target="_blank" rel="noopener"&gt;What's coming&lt;/A&gt; and the &lt;A href="https://docs.databricks.com/aws/en/release-notes/dev-tools/bundles" target="_blank" rel="noopener"&gt;Bundles release notes&lt;/A&gt;. The official guidance states that "the Terraform deployment engine will soon be deprecated."&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Why migrate proactively:&lt;/STRONG&gt; the migration will happen either way. Doing it on your own schedule lets you test each step and fix any issues in advance, rather than being migrated automatically on the cutover date.&lt;/P&gt;
&lt;H3&gt;Standard migration procedure&lt;/H3&gt;
&lt;P&gt;For a bundle currently on the Terraform engine, migrate &lt;STRONG&gt;one target at a time&lt;/STRONG&gt; (&lt;SPAN&gt;dev&lt;/SPAN&gt; → &lt;SPAN&gt;staging&lt;/SPAN&gt; → &lt;SPAN&gt;prod&lt;/SPAN&gt;), starting with the lowest-risk environment.&lt;/P&gt;
&lt;TABLE style="border-collapse: collapse; width: 100%; margin: 1em 0; background-color: #f6f8fa;"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style="border: 1px solid #d0d7de; padding: 12px 16px;"&gt;
&lt;PRE style="margin: 0; font-family: 'Roboto Mono','Courier New',monospace; font-size: 13px; line-height: 1.5; white-space: pre-wrap;"&gt;# 1. Deploy on Terraform first so the state is current (recommended).
databricks bundle deploy --target &amp;lt;env&amp;gt;

# 2. Add `engine: direct` to databricks.yml, then convert the state.
#    This reads terraform.tfstate and writes resources.json (the direct-engine state file).
databricks bundle deployment migrate --target &amp;lt;env&amp;gt;

# 3. Verify with a read-only plan. It must show 0 add / 0 change / 0 delete.
databricks bundle plan --target &amp;lt;env&amp;gt;

# 4. Finalize. This step is what persists the switch to the workspace.
databricks bundle deploy --target &amp;lt;env&amp;gt;&lt;/PRE&gt;
&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;P&gt;Enable the engine with a top-level key in &lt;SPAN&gt;databricks.yml&lt;/SPAN&gt;:&lt;/P&gt;
&lt;TABLE style="border-collapse: collapse; width: 100%; margin: 1em 0; background-color: #f6f8fa;"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style="border: 1px solid #d0d7de; padding: 12px 16px;"&gt;
&lt;PRE style="margin: 0; font-family: 'Roboto Mono','Courier New',monospace; font-size: 13px; line-height: 1.5; white-space: pre-wrap;"&gt;bundle:
  name: my_bundle
  engine: direct&lt;/PRE&gt;
&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;P&gt;You can also set it per target with &lt;SPAN&gt;targets.&amp;lt;env&amp;gt;.engine: direct&lt;/SPAN&gt;, or via the &lt;SPAN&gt;DATABRICKS_BUNDLE_ENGINE=direct&lt;/SPAN&gt; environment variable.&lt;/P&gt;
&lt;P&gt;Points confirmed by the official documentation:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;SPAN&gt;bundle deployment migrate&lt;/SPAN&gt; is &lt;STRONG&gt;local only&lt;/STRONG&gt;. It writes &lt;SPAN&gt;resources.json&lt;/SPAN&gt; (gitignored) and reads existing state IDs. Nothing changes server-side until step 4 (&lt;SPAN&gt;deploy&lt;/SPAN&gt;).&lt;/LI&gt;
&lt;LI&gt;&lt;SPAN&gt;bundle plan&lt;/SPAN&gt; is &lt;STRONG&gt;read-only&lt;/STRONG&gt;: it "displays the actions … without making any changes." This is the correct dry run.&lt;/LI&gt;
&lt;LI&gt;The plan may show small &lt;STRONG&gt;metadata-only differences&lt;/STRONG&gt; even when your configuration matches what is deployed. This is because the old Terraform state stored some fields that Databricks fills in automatically and that your bundle configuration does not include. These differences are harmless and are resolved on the next deploy.&lt;/LI&gt;
&lt;LI&gt;Requires &lt;STRONG&gt;CLI 1.3.0 or later&lt;/STRONG&gt; (direct engine GA). Use the latest 1.3.x or newer where possible.&lt;/LI&gt;
&lt;LI&gt;Direct-engine-only resource types (not deployable under Terraform): &lt;SPAN&gt;genie_spaces&lt;/SPAN&gt;, &lt;SPAN&gt;catalogs&lt;/SPAN&gt;, &lt;SPAN&gt;external_locations&lt;/SPAN&gt;, and Vector Search endpoints/indexes.&lt;/LI&gt;
&lt;LI&gt;Migration is permanent once completed. Do not re-run &lt;SPAN&gt;migrate&lt;/SPAN&gt; on an already-migrated target; it will error.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Rolling back before step 4:&lt;/STRONG&gt; delete &lt;SPAN&gt;resources.json&lt;/SPAN&gt; and restore &lt;SPAN&gt;terraform.tfstate&lt;/SPAN&gt; from the &lt;SPAN&gt;.backup&lt;/SPAN&gt; file that &lt;SPAN&gt;migrate&lt;/SPAN&gt; created (&lt;SPAN&gt;migrate&lt;/SPAN&gt; prints the exact paths). The workspace is unaffected until you deploy.&lt;/P&gt;
&lt;H4&gt;When is &lt;SPAN&gt;bind&lt;/SPAN&gt; required?&lt;/H4&gt;
&lt;P&gt;For a straightforward migration, &lt;SPAN&gt;bind&lt;/SPAN&gt; is &lt;STRONG&gt;not&lt;/STRONG&gt; required. &lt;SPAN&gt;migrate&lt;/SPAN&gt; converts the state in place, and every resource already managed by the bundle is carried over automatically. If you are only switching an existing bundle from Terraform to direct and changing nothing else, you can skip &lt;SPAN&gt;bind&lt;/SPAN&gt; and proceed to the cutover procedure.&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;bind&lt;/SPAN&gt; is a &lt;STRONG&gt;separate, optional step&lt;/STRONG&gt; that adopts a resource &lt;STRONG&gt;not yet present in the bundle's state&lt;/STRONG&gt;, so that DABs manages it without recreating it. The common case during a migration is adopting a resource that was previously managed outside the bundle, for example, a Genie space maintained by a custom API script, or a dashboard or job created manually in the UI. You bind the resource defined in your bundle to the live resource's ID so it is adopted rather than recreated. This is the worked example below.&lt;/P&gt;
&lt;P&gt;When you do this, run &lt;SPAN&gt;bind&lt;/SPAN&gt; as a deliberate cutover step, never as a quick test (see Item 1).&lt;/P&gt;
&lt;H3&gt;Behaviors worth knowing before you migrate&lt;/H3&gt;
&lt;P&gt;Each item notes briefly how it was established during this migration.&lt;/P&gt;
&lt;H4&gt;1. &lt;SPAN&gt;bundle deployment bind&lt;/SPAN&gt; persists to remote state before any deploy&lt;/H4&gt;
&lt;P&gt;&lt;EM&gt;Seen in a customer environment.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;This item applies only when you are adopting a resource with &lt;SPAN&gt;bind&lt;/SPAN&gt; (see "When is &lt;SPAN&gt;bind&lt;/SPAN&gt; required?" above). A plain migration does not use &lt;SPAN&gt;bind&lt;/SPAN&gt;.&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;bundle deployment bind KEY RESOURCE_ID&lt;/SPAN&gt; links an existing workspace resource to one defined in your bundle, so that DABs manages it without recreating it. The command is documented on the &lt;A href="https://docs.databricks.com/aws/en/dev-tools/bundles/migrate-resources" target="_blank" rel="noopener"&gt;Migrate existing resources to a bundle&lt;/A&gt; page. A detail worth calling out is its timing: &lt;SPAN&gt;bind&lt;/SPAN&gt; writes to the workspace's deployment state immediately, before you run &lt;SPAN&gt;deploy&lt;/SPAN&gt;. Because of this, running &lt;SPAN&gt;migrate&lt;/SPAN&gt; and then &lt;SPAN&gt;bind&lt;/SPAN&gt; against a shared target is not a safe way to "test" a migration; it changes real state.&lt;/P&gt;
&lt;P&gt;What happened in practice: running &lt;SPAN&gt;migrate → bind → plan&lt;/SPAN&gt; against production as a test left the state ahead of the configuration, and a later routine deployment was blocked by the safety gate (Item 2). The Case study below describes this incident in full.&lt;/P&gt;
&lt;P&gt;Guidance:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Treat this timing as observed behavior, verified during the migration.&lt;/LI&gt;
&lt;LI&gt;The only read-only command is &lt;SPAN&gt;bundle plan&lt;/SPAN&gt;; it is the only safe way to preview a migration. When you genuinely need to adopt a resource, run &lt;SPAN&gt;bind&lt;/SPAN&gt; as part of a real cutover (&lt;SPAN&gt;migrate → bind → plan → deploy&lt;/SPAN&gt;), never against a shared or production target as a test.&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;2. The destructive-action gate aborts the entire deployment&lt;/H4&gt;
&lt;P&gt;Under the direct engine, if a &lt;SPAN&gt;bundle deploy&lt;/SPAN&gt; would &lt;STRONG&gt;delete or recreate&lt;/STRONG&gt; any resource, the CLI aborts the &lt;STRONG&gt;entire&lt;/STRONG&gt; deployment (not only the affected resource) unless an explicit bypass flag is passed. In non-interactive CI, it fails with: "the deployment requires destructive actions, but the current console does not support prompting."&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;This is a safety mechanism. If one resource is set to be deleted or recreated, it blocks all other resources (jobs, pipelines, and so on) from deploying too. The benefit is that nothing is deleted by surprise; the cost is that one unexpected deletion can block the whole deployment.&lt;/LI&gt;
&lt;LI&gt;The CLI prints a note advising automated agents not to retry with the bypass flag. Fix the underlying cause rather than bypassing the gate. During a migration, this gate is what protects you if a &lt;SPAN&gt;bind&lt;/SPAN&gt; step (Item 1) left the state and configuration out of sync.&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;3. Run &lt;SPAN&gt;migrate&lt;/SPAN&gt; before &lt;SPAN&gt;bind&lt;/SPAN&gt;&lt;/H4&gt;
&lt;P&gt;When adopting a direct-engine-only resource (such as a Genie space) during migration, run &lt;SPAN&gt;migrate&lt;/SPAN&gt; first. Running &lt;SPAN&gt;bundle deployment bind&lt;/SPAN&gt; while the bundle is still on the Terraform engine fails with &lt;SPAN&gt;no converter for resource type genie_spaces&lt;/SPAN&gt;. This is not specific to Genie spaces; it happens for any direct-engine-only resource type added to a Terraform-engine bundle, because these types have no converter under the Terraform provider. Run &lt;SPAN&gt;migrate&lt;/SPAN&gt; (which converts the state to direct) and then &lt;SPAN&gt;bind&lt;/SPAN&gt;.&lt;/P&gt;
&lt;H4&gt;4. A service principal cannot own a Genie space&lt;/H4&gt;
&lt;P&gt;There is no &lt;SPAN&gt;IS_OWNER&lt;/SPAN&gt; permission level for &lt;SPAN&gt;genie_spaces&lt;/SPAN&gt; and no ownership-transfer path for them (unlike dashboards, queries, and alerts). If your bundle deploys as a service principal, the Genie space must retain a &lt;STRONG&gt;human owner&lt;/STRONG&gt;. Grant the deploy service principal &lt;SPAN&gt;CAN_MANAGE&lt;/SPAN&gt; so that DABs can update the space's content. Note that &lt;SPAN&gt;run_as&lt;/SPAN&gt; on a Genie space is an execution setting, not an ownership assignment.&lt;/P&gt;
&lt;H4&gt;5. Bundles that deploy as a service principal with &lt;SPAN&gt;run_as&lt;/SPAN&gt; must be migrated in CI&lt;/H4&gt;
&lt;P&gt;A bundle with &lt;SPAN&gt;run_as: &amp;lt;service-principal&amp;gt;&lt;/SPAN&gt; and any dashboards using &lt;SPAN&gt;embed_credentials: true&lt;/SPAN&gt; will fail local validation for a human user (&lt;SPAN&gt;… do not support a run_as user different from the owner&lt;/SPAN&gt;), because your local identity differs from the &lt;SPAN&gt;run_as&lt;/SPAN&gt; service principal. CI succeeds because it runs &lt;STRONG&gt;as&lt;/STRONG&gt; the service principal (the running identity matches &lt;SPAN&gt;run_as&lt;/SPAN&gt;). So the only reliable way to preview the migration for such a bundle is a &lt;STRONG&gt;read-only&lt;/STRONG&gt; &lt;SPAN&gt;bundle plan&lt;/SPAN&gt; run in CI as the service principal, for example, a plan-only workflow on a temporary branch. Do not run &lt;SPAN&gt;migrate&lt;/SPAN&gt;, &lt;SPAN&gt;bind&lt;/SPAN&gt;, or &lt;SPAN&gt;deploy&lt;/SPAN&gt; in that preview workflow.&lt;/P&gt;
&lt;H3&gt;Example: adopting a Genie space into the bundle&lt;/H3&gt;
&lt;P&gt;Native Genie support is one of the primary benefits of the direct engine, so it is worth a complete walkthrough. &lt;SPAN&gt;genie_spaces&lt;/SPAN&gt; is a direct-engine-only resource type; it does not exist under the Terraform engine. Before the direct engine, a Genie space could only be managed outside the bundle.&lt;/P&gt;
&lt;H4&gt;Before: Genie space managed by an API script&lt;/H4&gt;
&lt;P&gt;Teams typically maintained the space with a custom deployment script that called the Genie REST API on each change, together with a JSON representation of the space definition checked into the repository:&lt;/P&gt;
&lt;TABLE style="border-collapse: collapse; width: 100%; margin: 1em 0; background-color: #f6f8fa;"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style="border: 1px solid #d0d7de; padding: 12px 16px;"&gt;
&lt;PRE style="margin: 0; font-family: 'Roboto Mono','Courier New',monospace; font-size: 13px; line-height: 1.5; white-space: pre-wrap;"&gt;scripts/deploy_genie_space.py      # custom code that PATCHes the space via the /genie/spaces API
src/genie_space_definition.json    # the space content, maintained by hand&lt;/PRE&gt;
&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;P&gt;This approach has several drawbacks: the space is managed outside the bundle (a separate CI step with its own authentication and its own way of failing), the JSON format is custom, there is no &lt;SPAN&gt;plan&lt;/SPAN&gt; step to preview changes, and the space is not deployed together with the dashboards and jobs it relates to.&lt;/P&gt;
&lt;H4&gt;After: Genie space as a native &lt;SPAN&gt;genie_spaces&lt;/SPAN&gt; resource&lt;/H4&gt;
&lt;P&gt;Once the bundle is on the direct engine, generate the resource from the &lt;STRONG&gt;existing&lt;/STRONG&gt; live space so that nothing is recreated:&lt;/P&gt;
&lt;TABLE style="border-collapse: collapse; width: 100%; margin: 1em 0; background-color: #f6f8fa;"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style="border: 1px solid #d0d7de; padding: 12px 16px;"&gt;
&lt;PRE style="margin: 0; font-family: 'Roboto Mono','Courier New',monospace; font-size: 13px; line-height: 1.5; white-space: pre-wrap;"&gt;# Generates resources/&amp;lt;key&amp;gt;.genie_space.yml and a serialized &amp;lt;key&amp;gt;.geniespace.json content file.
databricks bundle generate genie-space \
  --existing-id &amp;lt;existing_genie_space_id&amp;gt; \
  --key my_genie_space&lt;/PRE&gt;
&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;P&gt;This produces a resource definition similar to the following:&lt;/P&gt;
&lt;TABLE style="border-collapse: collapse; width: 100%; margin: 1em 0; background-color: #f6f8fa;"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style="border: 1px solid #d0d7de; padding: 12px 16px;"&gt;
&lt;PRE style="margin: 0; font-family: 'Roboto Mono','Courier New',monospace; font-size: 13px; line-height: 1.5; white-space: pre-wrap;"&gt;# resources/my_genie_space.genie_space.yml
resources:
  genie_spaces:
    my_genie_space:
      title: "My Genie Space"
      warehouse_id: ${var.warehouse_id}
      parent_path: /Workspace/Shared/my_project
      # file_path points at the generated serialized content.
      file_path: ../src/my_genie_space.geniespace.json
      permissions:
        # A service principal cannot own a Genie space (Item 4). Keep a human owner
        # and grant the deploy service principal CAN_MANAGE so DABs can update content.
        - level: CAN_MANAGE
          service_principal_name: &amp;lt;deploy-service-principal&amp;gt;
        - level: CAN_MANAGE
          user_name: &amp;lt;human-owner&amp;gt;&lt;/PRE&gt;
&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;H4&gt;Adopt the existing space rather than recreating it&lt;/H4&gt;
&lt;P&gt;The objective is to take over the live space, including its conversation history, rather than create a new one. Once the resource exists in configuration:&lt;/P&gt;
&lt;TABLE style="border-collapse: collapse; width: 100%; margin: 1em 0; background-color: #f6f8fa;"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD style="border: 1px solid #d0d7de; padding: 12px 16px;"&gt;
&lt;PRE style="margin: 0; font-family: 'Roboto Mono','Courier New',monospace; font-size: 13px; line-height: 1.5; white-space: pre-wrap;"&gt;# 1. Migrate the bundle to direct first. bind fails under Terraform with
#    "no converter for resource type genie_spaces" (Item 3).
databricks bundle deployment migrate --target &amp;lt;env&amp;gt;

# 2. Adopt the live space into the bundle state by its ID.
databricks bundle deployment bind my_genie_space &amp;lt;existing_genie_space_id&amp;gt; --target &amp;lt;env&amp;gt;

# 3. Run a read-only plan. The space should appear as an in-place update, not a create + delete.
databricks bundle plan --target &amp;lt;env&amp;gt;

# 4. Deploy to finalize (in CI as the service principal for run_as bundles).
databricks bundle deploy --target &amp;lt;env&amp;gt;&lt;/PRE&gt;
&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;P&gt;A clean adoption reports the space as an &lt;STRONG&gt;in-place update&lt;/STRONG&gt; with its &lt;STRONG&gt;ID preserved&lt;/STRONG&gt;, for example, &lt;SPAN&gt;1 to add&lt;/SPAN&gt; (the permissions block), &lt;SPAN&gt;2 to change&lt;/SPAN&gt;, &lt;SPAN&gt;0 to delete&lt;/SPAN&gt;, with everything else unchanged. The space and its conversation history are retained.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Note: as in Item 1, this &lt;SPAN&gt;bind&lt;/SPAN&gt; persists to remote state, so preview with a plan first and run &lt;SPAN&gt;migrate → bind → deploy&lt;/SPAN&gt; only as a deliberate cutover, never as a test against production.&lt;/STRONG&gt;&lt;/P&gt;
&lt;H4&gt;Retire the previous approach&lt;/H4&gt;
&lt;P&gt;Once the DAB-managed space deploys cleanly and you have verified the title, ID, and queries, remove the previous &lt;SPAN&gt;deploy_genie_space.py&lt;/SPAN&gt; script and the legacy JSON file in a follow-up change. Retain them until the DAB-managed path is proven, then remove them so that there is a single source of truth.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Result:&lt;/STRONG&gt; the Genie space now resides in the same bundle as the dashboards and jobs that feed it, receives the same &lt;SPAN&gt;plan&lt;/SPAN&gt;, review, and CI treatment as every other resource, and no longer requires a separate API script.&lt;/P&gt;
&lt;H3&gt;Recommended production cutover procedure&lt;/H3&gt;
&lt;P&gt;The production cutover follows the standard procedure above, with two production-specific points. Deploy in CI as the service principal for &lt;SPAN&gt;run_as&lt;/SPAN&gt; bundles, and run &lt;SPAN&gt;bind&lt;/SPAN&gt; only for a resource you are genuinely adopting.&lt;/P&gt;
&lt;P&gt;Gate before deploying: the plan must show 0 delete / 0 recreate. Metadata-only differences (see the standard procedure) are acceptable. Any create + delete or recreate means something is wrong; stop, do not deploy, and fix the &lt;SPAN&gt;bind&lt;/SPAN&gt; step first.&lt;/P&gt;
&lt;P&gt;After the deploy, verify the result: the Genie space ID is unchanged, the apps are still running, and no service principal was changed.&lt;/P&gt;
&lt;P&gt;Do not run &lt;SPAN&gt;migrate&lt;/SPAN&gt;, &lt;SPAN&gt;bind&lt;/SPAN&gt;, or &lt;SPAN&gt;deploy&lt;/SPAN&gt; against production as a test. Preview with &lt;SPAN&gt;bundle plan&lt;/SPAN&gt; only.&lt;/P&gt;
&lt;H3&gt;Case study&lt;/H3&gt;
&lt;P&gt;I was migrating a single large bundle (jobs, dashboards, a Genie space, and two Apps, deploying as a service principal). To make sure the production cutover would be safe, I ran &lt;SPAN&gt;migrate → bind → plan&lt;/SPAN&gt; against &lt;STRONG&gt;production&lt;/STRONG&gt; first, as a test.&lt;/P&gt;
&lt;P&gt;The plan looked clean. But the &lt;SPAN&gt;bind&lt;/SPAN&gt; step had already changed production's state: it switched production to the direct engine and added the Genie space to the state, even though the configuration that defined the Genie space was still in an unmerged pull request. A few days later, my colleague's normal deployment ran. It compared the configuration (no Genie space) against the state (Genie space present), decided to &lt;STRONG&gt;delete&lt;/STRONG&gt; it, hit the safety gate, and blocked all production deployments; not just Genie changes. Nothing was actually deleted (the gate stopped it, and the space and its history were safe), but production stayed blocked until the pull request was merged.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Root cause:&lt;/STRONG&gt; treating &lt;SPAN&gt;migrate&lt;/SPAN&gt; and &lt;SPAN&gt;bind&lt;/SPAN&gt; as a test. &lt;STRONG&gt;Lesson:&lt;/STRONG&gt; the only safe way to preview a migration is &lt;SPAN&gt;bundle plan&lt;/SPAN&gt;. &lt;SPAN&gt;bind&lt;/SPAN&gt; changes state on its own, without a &lt;SPAN&gt;deploy&lt;/SPAN&gt;. A clean plan only tells you the plan step succeeded; the bind before it had already changed the state.&lt;/P&gt;
&lt;H3&gt;Summary checklist&lt;/H3&gt;
&lt;UL&gt;
&lt;LI&gt;[ ] CLI 1.3.0 or later (ideally the latest 1.3.x or newer).&lt;/LI&gt;
&lt;LI&gt;[ ] Add &lt;SPAN&gt;engine: direct&lt;/SPAN&gt;; migrate one target at a time, lowest-risk environment first.&lt;/LI&gt;
&lt;LI&gt;[ ] Use &lt;SPAN&gt;bundle plan&lt;/SPAN&gt; as the only way to preview. Do not run &lt;SPAN&gt;migrate&lt;/SPAN&gt; or &lt;SPAN&gt;bind&lt;/SPAN&gt; against a shared or production target to test.&lt;/LI&gt;
&lt;LI&gt;[ ] For service-principal bundles, run &lt;SPAN&gt;migrate&lt;/SPAN&gt;, &lt;SPAN&gt;plan&lt;/SPAN&gt;, and &lt;SPAN&gt;deploy&lt;/SPAN&gt; in CI as the service principal, not locally.&lt;/LI&gt;
&lt;LI&gt;[ ] Gate on 0 delete / 0 recreate before deploying (metadata-only differences are acceptable).&lt;/LI&gt;
&lt;LI&gt;[ ] For a Genie space, generate the resource from the existing ID, then &lt;SPAN&gt;migrate → bind → plan → deploy&lt;/SPAN&gt; to adopt it in place; keep a human owner and grant the deploy service principal &lt;SPAN&gt;CAN_MANAGE&lt;/SPAN&gt;; retire the previous API script afterward.&lt;/LI&gt;
&lt;LI&gt;[ ] After cutover, verify the Genie space ID and apps are unchanged.&lt;/LI&gt;
&lt;/UL&gt;
&lt;H3&gt;Sources and further reading&lt;/H3&gt;
&lt;UL&gt;
&lt;LI&gt;Official documentation: &lt;A href="https://docs.databricks.com/aws/en/dev-tools/bundles/direct" target="_blank" rel="noopener"&gt;Migrate to the direct deployment engine&lt;/A&gt; · &lt;A href="https://docs.databricks.com/aws/en/dev-tools/cli/bundle-commands" target="_blank" rel="noopener"&gt;bundle command group&lt;/A&gt; · &lt;A href="https://docs.databricks.com/aws/en/dev-tools/bundles/migrate-resources" target="_blank" rel="noopener"&gt;Migrate existing resources to a bundle&lt;/A&gt; · &lt;A href="https://docs.databricks.com/aws/en/release-notes/whats-coming" target="_blank" rel="noopener"&gt;What's coming&lt;/A&gt; · &lt;A href="https://docs.databricks.com/aws/en/release-notes/dev-tools/bundles" target="_blank" rel="noopener"&gt;Bundles release notes&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;Internal engineering design documents exist for the engine internals. At the time of writing, there is no field-authored generic migration runbook, which is the motivation for this guide. Several of the behaviors above come from hands-on migration experience.&lt;/LI&gt;
&lt;/UL&gt;</description>
    <pubDate>Tue, 18 Aug 2026 09:25:25 GMT</pubDate>
    <dc:creator>himanshu_ranjan</dc:creator>
    <dc:date>2026-08-18T09:25:25Z</dc:date>
    <item>
      <title>DABs Migration Guide: Terraform to the Direct Deployment Engine</title>
      <link>https://community.databricks.com/t5/technical-blog/dabs-migration-guide-terraform-to-the-direct-deployment-engine/ba-p/165694</link>
      <description>&lt;P&gt;A guide to migrate an existing Declarative Automation Bundle from the Terraform deployment engine to the direct deployment engine. It covers the standard procedure, when bundle deployment bind is required, and five behaviours that surfaced during a customer migration, and a worked example of adopting a Genie space into the bundle.&lt;/P&gt;</description>
      <pubDate>Tue, 18 Aug 2026 09:25:25 GMT</pubDate>
      <guid>https://community.databricks.com/t5/technical-blog/dabs-migration-guide-terraform-to-the-direct-deployment-engine/ba-p/165694</guid>
      <dc:creator>himanshu_ranjan</dc:creator>
      <dc:date>2026-08-18T09:25:25Z</dc:date>
    </item>
    <item>
      <title>Re: DABs Migration Guide: Terraform to the Direct Deployment Engine</title>
      <link>https://community.databricks.com/t5/technical-blog/dabs-migration-guide-terraform-to-the-direct-deployment-engine/bc-p/166064#M1176</link>
      <description>&lt;P&gt;Hi&amp;nbsp;&lt;a href="https://community.databricks.com/t5/user/viewprofilepage/user-id/228703"&gt;@himanshu_ranjan&lt;/a&gt;,&lt;BR /&gt;&amp;nbsp;&lt;BR /&gt;thanks for the heads-up!&lt;/P&gt;&lt;P&gt;Genie Agents (still genie_spaces as a bundle resource type) landed in bundles because the Terraform provider has no equivalent resource, and the direct engine removed the requirement to wait for a provider release. Fair enough.&lt;/P&gt;&lt;P&gt;But that decoupling means the set of bundle-deployable resources will now grow faster than the provider's, and it has already reached infrastructure-shaped objects, namely catalogs and external locations are direct-engine bundle resources today, and those sit squarely in most platform teams' Terraform.&lt;/P&gt;&lt;P&gt;So is there a stated principle for which layer owns what going forward, or does it land wherever ships first?&lt;/P&gt;&lt;P&gt;Specifically, if the provider eventually adds a Genie resource, is the guidance to move or to stay in bundles? My own view is stay in DABs since a Genie Agent isn't really infrastructure, it's instructions, example queries and trusted assets that change with the data model, so it belongs next to the pipelines it describes. But I'd rather know if that's the intended direction.&lt;/P&gt;&lt;P&gt;And for a resource both layers can manage, is there anything preventing two tools from claiming the same object, or is that purely down to team discipline?&lt;/P&gt;</description>
      <pubDate>Thu, 20 Aug 2026 13:22:11 GMT</pubDate>
      <guid>https://community.databricks.com/t5/technical-blog/dabs-migration-guide-terraform-to-the-direct-deployment-engine/bc-p/166064#M1176</guid>
      <dc:creator>Armanillo_RoK</dc:creator>
      <dc:date>2026-08-20T13:22:11Z</dc:date>
    </item>
    <item>
      <title>Re: DABs Migration Guide: Terraform to the Direct Deployment Engine</title>
      <link>https://community.databricks.com/t5/technical-blog/dabs-migration-guide-terraform-to-the-direct-deployment-engine/bc-p/166085#M1177</link>
      <description>&lt;P&gt;Thanks &lt;a href="https://community.databricks.com/t5/user/viewprofilepage/user-id/235827"&gt;@Armanillo_RoK&lt;/a&gt;&amp;nbsp;for reading it closely, and glad it was useful. You've read the decoupling correctly: because the direct engine no longer waits on a Terraform provider release, the set of bundle-supported resources can grow on its own, and it now reaches infrastructure-shaped objects like catalogs and external locations.&lt;/P&gt;
&lt;P&gt;On which layer owns what, there's actually a stated recommendation, not just "wherever ships first." The Databricks deployment guide (the IaC section) suggests Terraform for infrastructure like workspaces, networking, Unity Catalog and storage, and Bundles for data and AI workloads, where it lists jobs, pipelines, notebooks and models:&lt;BR /&gt;&lt;A href="https://docs.databricks.com/aws/en/lakehouse-architecture/deployment-guide/iac" target="_blank"&gt;https://docs.databricks.com/aws/en/lakehouse-architecture/deployment-guide/iac&lt;/A&gt;&lt;BR /&gt;&lt;BR /&gt;Being able to deploy catalogs and external locations from a bundle is a new capability, but it doesn't move that recommendation. By default those still sit with the platform team's Terraform. I'd only manage one from a bundle as a deliberate, agreed exception. For example, a self-contained catalog that belongs to a single workload, where the platform team has decided to leave it to that team instead of managing it centrally.&lt;/P&gt;
&lt;P&gt;On Genie, I'd keep it in the bundle, for the reason you gave. A Genie space isn't really infrastructure, it's instructions, sample questions and trusted assets that move with the data model, so it belongs next to the pipelines it describes. Terraform provider support for Genie is an open feature request, not something available today, and even if it lands I'd let ownership decide rather than the fact that a new resource exists. A Genie space tied to a data product stays in the bundle.&lt;/P&gt;
&lt;P&gt;On two tools managing the same object, there isn't a cross-tool safeguard. Bundles on the direct engine keep their own deployment state and Terraform keeps its own state file, and neither one knows about the other, so each can think it's authoritative. bundle deployment bind and Terraform's import are explicit ways to adopt an existing resource, not conflict detectors. So the real guardrail is ownership: one authoritative tool per object, usually split by team, with the platform team owning the Terraform repo and the data engineers owning the bundle, and the bundle referencing infra objects by name instead of redeclaring them. When you do move ownership between the two, do it deliberately and check with a plan that shows no unintended create, replace or delete. That's why I lean on bundle plan as the safe preview in the post.&lt;/P&gt;</description>
      <pubDate>Thu, 20 Aug 2026 17:40:22 GMT</pubDate>
      <guid>https://community.databricks.com/t5/technical-blog/dabs-migration-guide-terraform-to-the-direct-deployment-engine/bc-p/166085#M1177</guid>
      <dc:creator>himanshu_ranjan</dc:creator>
      <dc:date>2026-08-20T17:40:22Z</dc:date>
    </item>
    <item>
      <title>Re: DABs Migration Guide: Terraform to the Direct Deployment Engine</title>
      <link>https://community.databricks.com/t5/technical-blog/dabs-migration-guide-terraform-to-the-direct-deployment-engine/bc-p/166098#M1178</link>
      <description>&lt;P&gt;Great post, I wasn't aware of the change and helps me learn about it. Will greatly benefit one of my customers!&lt;/P&gt;</description>
      <pubDate>Fri, 21 Aug 2026 02:20:21 GMT</pubDate>
      <guid>https://community.databricks.com/t5/technical-blog/dabs-migration-guide-terraform-to-the-direct-deployment-engine/bc-p/166098#M1178</guid>
      <dc:creator>EduardoLomonaco</dc:creator>
      <dc:date>2026-08-21T02:20:21Z</dc:date>
    </item>
    <item>
      <title>Re: DABs Migration Guide: Terraform to the Direct Deployment Engine</title>
      <link>https://community.databricks.com/t5/technical-blog/dabs-migration-guide-terraform-to-the-direct-deployment-engine/bc-p/166121#M1179</link>
      <description>&lt;P&gt;Tnx, helpful guide!&lt;BR /&gt;&lt;BR /&gt;However I do notice that the direct engine still lacks some functionality.&lt;BR /&gt;fetching values from cluster policies apparently is only partially implemented.&lt;BR /&gt;I had Genie make me a nice summary :-):&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Summary:&lt;/STRONG&gt; After migrating from the Terraform engine to the direct engine, jobs with apply_policy_default_values: true are flagged as "changed" on every bundle plan / bundle deploy, even when no YAML changes were made. This creates an infinite update loop because the cluster policy re-injects the same values after each deploy.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Current behavior:&lt;/STRONG&gt; The direct engine correctly skips some policy/platform-populated fields:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;azure_attributes → "action": "skip", "reason": "managed"&lt;/LI&gt;&lt;LI&gt;data_security_mode → "action": "skip", "reason": "backend_default"&lt;/LI&gt;&lt;LI&gt;enable_elastic_disk → "action": "skip", "reason": "backend_default"&lt;/LI&gt;&lt;LI&gt;node_type_id → "action": "skip", "reason": "backend_default"&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;But it flags these policy-injected fields as "action": "update":&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;spark_env_vars&lt;/LI&gt;&lt;LI&gt;spark_version&lt;/LI&gt;&lt;LI&gt;spark_conf&lt;/LI&gt;&lt;LI&gt;custom_tags (e.g. ResourceClass: SingleNode)&lt;/LI&gt;&lt;LI&gt;runtime_engine&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;&lt;STRONG&gt;Expected behavior:&lt;/STRONG&gt; When apply_policy_default_values: true is set on a job cluster, the engine should recognize that the policy is the source of truth for fields not declared in the bundle YAML. Fields present in remote state but absent from local config — that are injected by the referenced policy_id — should be treated as "action": "skip", "reason": "managed" (or a new reason like "policy_default"), not as removals.&lt;/P&gt;</description>
      <pubDate>Fri, 21 Aug 2026 08:47:24 GMT</pubDate>
      <guid>https://community.databricks.com/t5/technical-blog/dabs-migration-guide-terraform-to-the-direct-deployment-engine/bc-p/166121#M1179</guid>
      <dc:creator>-werners-</dc:creator>
      <dc:date>2026-08-21T08:47:24Z</dc:date>
    </item>
    <item>
      <title>Re: DABs Migration Guide: Terraform to the Direct Deployment Engine</title>
      <link>https://community.databricks.com/t5/technical-blog/dabs-migration-guide-terraform-to-the-direct-deployment-engine/bc-p/166190#M1183</link>
      <description>&lt;P&gt;Thanks &lt;a href="https://community.databricks.com/t5/user/viewprofilepage/user-id/14792"&gt;@-werners-&lt;/a&gt;, glad the guide helped.&lt;/P&gt;
&lt;P&gt;Your question is a bit outside what the blog covers. What you are seeing is a different thing: how the direct engine compares the values your cluster policy fills in each time you plan or deploy.&lt;/P&gt;
&lt;P&gt;It's a known issue and it is being worked on. A recent CLI fix made the engine leave apply_policy_default_values, data_security_mode, enable_elastic_disk, node_type_id and a few others alone, which is why you see those skipped. The ones you listed, spark_conf, spark_version, spark_env_vars, runtime_engine and custom_tags, are not handled yet, so they still show up as an update every time.&lt;/P&gt;
&lt;P&gt;A quick workaround is to set those fields yourself in the bundle YAML. Then your config matches what the policy adds and the diff goes away. You lose a little of the benefit of the policy, but it stops the constant changes until the engine catches up.&lt;/P&gt;</description>
      <pubDate>Fri, 21 Aug 2026 21:01:06 GMT</pubDate>
      <guid>https://community.databricks.com/t5/technical-blog/dabs-migration-guide-terraform-to-the-direct-deployment-engine/bc-p/166190#M1183</guid>
      <dc:creator>himanshu_ranjan</dc:creator>
      <dc:date>2026-08-21T21:01:06Z</dc:date>
    </item>
  </channel>
</rss>

