CertSafari
    DBT Analytics Engineering· Lessons

    Domain 4 · Lesson 24/31

    dbt clone: zero-copy clones, pointer views and CI

    Using dbt clone

    13 min read
    3.23% of exam
    3 sources
    Published 12 Oct 2026
    Docs as of 12 Oct 2026

    What you will be able to do

    • Predict whether dbt clone creates a zero-copy clone or a pointer view for a given warehouse and relation
    • Use --state, --select, --full-refresh and --threads with dbt clone correctly
    • Choose between dbt clone and deferral for development, BI testing and blue/green deployment
    • Clone pre-existing incremental models as the first step of a slim CI job, and explain why state:old belongs in the selector

    Key concept

    Clone materialization — dbt clone reads a manifest from another environment and recreates the selected nodes in your current target. Where the warehouse supports zero-copy cloning and the source object is a table, dbt creates a real clone. Everywhere else it creates a view that selects from the source object.

    1.What dbt clone creates in your target

    dbt clone copies objects from one environment into another without running any model SQL. It arrived in dbt v1.6, alongside dbt retry, as part of a set of features for running mature deployments at scale. You point it at the artifacts of another run with --state, typically the manifest.json from a production job. dbt then works out where each selected node lives in that environment and creates a matching object in the schema(s) of your current target. The command uses a dedicated clone materialization, and the object it produces depends on two things: the warehouse you are on and what the source object is.

    Zero-copy cloning only happens when both conditions hold. The warehouse must support zero-copy cloning of tables (Snowflake, Databricks or BigQuery), and the node must exist as a table in the source environment. In that case dbt creates a clone that shares the underlying storage, so no data is duplicated. If either condition fails, for example on a warehouse without zero-copy cloning or for a model that is a view in production, dbt creates a pointer view: select * from the source object. A pointer view is cheap to create, but every query against it still reads the production relation.

    What dbt clone creates, by platform and source object
    SituationObject created in your target
    Snowflake, Databricks or BigQuery, and the model is a table in the source environmentZero-copy clone of the table
    Warehouse without zero-copy cloning of tablesPointer view (select * from the source object)
    Model is not a table in the source environmentPointer view (select * from the source object)

    Checkpoint 1 of 9· Check yourself

    An analytics engineer runs dbt clone --state prod-artifacts into their dev schema on a warehouse that does not support zero-copy cloning. In production, fct_orders is a table. What does dbt create in the dev schema for fct_orders?

    By default, dbt clone leaves existing relations alone. If your dev schema already contains fct_orders from last week's work, a plain dbt clone --state ... skips it and clones only what is missing. That default protects work in progress, but it also means stale objects stay stale. To replace everything in the selection with a fresh clone of the source state, add --full-refresh. Selection works the same way it does for other commands: --select limits the clone to particular nodes. Each clone statement is independent of the others, so raising --threads well above your usual run setting shortens a large clone.

    The four forms of dbt clone: everything, one model, recreate existing relations, and high parallelismbash
    # clone all of my models from specified state to my target schema(s)
    dbt clone --state path/to/artifacts
    
    # clone one_specific_model of my models from specified state to my target schema(s)
    dbt clone --select "one_specific_model" --state path/to/artifacts
    
    # clone all of my models from specified state to my target schema(s) and recreate all pre-existing relations in the current target
    dbt clone --state path/to/artifacts --full-refresh
    
    # clone all of my models from specified state to my target schema(s), running up to 50 clone statements in parallel
    dbt clone --state path/to/artifacts --threads 50

    Checkpoint 2 of 9· Check yourself

    Your dev schema already contains a week-old dim_customers. You run dbt clone --state prod-artifacts with no other flags. What happens to dim_customers?

    Checkpoint 3 of 9· Exam question

    A Snowflake-backed project's Slim CI job takes 40 minutes because a 200 GB incremental model with `on_schema_change: fail` runs a full refresh on every pull request, since the model does not yet exist in the PR-specific schema. The team wants CI to exercise the same incremental path that runs in production without rebuilding the full history each time. Which action addresses this while keeping the incremental behavior test accurate?

    Sources12

    2.When to clone and when to defer

    dbt clone is built on deferral but costs more than deferral. Deferral, covered with state selection in [state and deferral](lesson:7.1), rewrites the ref calls for unselected nodes so they point at production, and it creates nothing extra. dbt clone does create objects. It uses some warehouse compute and leaves new relations in your schema. In many cases deferral is the cheaper and simpler choice. Clone earns its cost when something outside dbt needs to find real objects in your schema.

    Each of these situations needs real objects in the target:

    - Blue/green continuous deployment, on warehouses that support zero-copy cloning of tables. - Cloning the current production state into development schemas, so a dev environment is populated without running the full pipeline. - Handling incremental models in CI jobs, on warehouses that support zero-copy cloning. - Testing code changes on downstream dependencies in a BI tool, which can only query objects that exist in the warehouse.

    The BI case shows the difference most clearly. Deferral only changes how dbt compiles SQL, so a dashboard pointed at your dev schema finds no tables there. After a clone, the dashboard can query the dev schema directly. The same reasoning applies to promotion. Because clone creates lightweight copies across environments, it can move specific models from a staging environment into production.

    Checkpoint 4 of 9· Check yourself

    A developer wants to check that a dashboard still renders after changing dim_customers. The dashboard is pointed at their dev schema, which is empty apart from the modified model. Which approach lets the dashboard read every upstream table?

    How you set up defer depends on where you run clone. In the dbt platform CLI, dbt clone includes --defer automatically, so the command works with no extra setup. The Studio IDE needs three things first: a Production environment with at least one successful job run, the Defer to production toggle switched on in the lower-right corner of the command bar, and then the dbt clone command run from the command bar.

    Checkpoint 5 of 9· Put it in order

    Put the steps for running dbt clone in the Studio IDE in order

    1. 1.Run the dbt clone command from the command bar
    2. 2.Set up a Production environment and have a successful job run
    3. 3.Enable the Defer to production toggle in the command bar

    Checkpoint 6 of 9· Exam question

    A CI pipeline runs this command before building modified models on a Snowflake project: ``` dbt clone --select state:modified+,config.materialized:incremental --state path/to/prod/artifacts ``` A brand-new incremental model included in this pull request fails to clone with an error that no relation exists in production. Which part of the selection expression is causing this?

    Sources12

    3.Cloning incremental models in slim CI

    A slim CI job builds into a fresh PR-specific schema, and incremental models do not handle that well. A typical job defers to production, runs dbt build --select state:modified+, and is triggered by every pull request against main. Suppose a PR modifies dim_wizards. The job builds dim_wizards and its downstream fct_orders into a temporary schema created for that PR.

    That full rebuild causes two problems. Incremental models are usually the largest datasets in a project, so rebuilding them on every PR is slow and expensive. The rebuild also tests the wrong path. A full refresh can pass in CI even when the incremental run in production will fail after merge. The fix is to clone the pre-existing incremental models into the PR schema before the build runs. When dbt build starts, those models already exist, is_incremental is true, and CI runs the same code path that production will. This only works on warehouses with zero-copy cloning. Anywhere else, the clone step produces pointer views.

    Checkpoint 7 of 9· Fill the gap

    Which selector completes the clone step so that brand new incremental models are not cloned?

    dbt clone --select state:modified+,config.materialized:incremental, ? 

    The comma-separated selector is an intersection, and each part has a job. state:modified+ picks modified models and everything downstream of them. config.materialized:incremental keeps only the incremental ones. state:old drops nodes that are new in this PR. A brand-new incremental model has nothing in production to clone, and it will run as a full refresh once merged, so CI should run it as a full refresh too. Without state:old, the command still works but logs "No relation found in state manifest for…". Adding state:old states the intent explicitly. The second step is the usual dbt build --select state:modified+.

    Cloning also brings schema-change failures into CI, and you need to decide how to handle them. Consider an incremental model with on_schema_change='fail' and a PR that adds a column. An incremental build of that model fails, while a full refresh succeeds. With the clone step in place, CI fails the way production will after merge. The alternative is a green CI check followed by a failing nightly dbt build. dbt Labs prefers the failing CI job: someone manually overrides the branch protection rule and then runs dbt build --full-refresh --select my_incremental_model in production right after merge.

    An incremental model configured to fail on schema changesql
    {{
        config(
            materialized='incremental',
            unique_key='unique_id',
            on_schema_change='fail'
        )
    }}

    Checkpoint 8 of 9· Check yourself

    A PR adds a column to an incremental model configured with on_schema_change='fail'. CI clones the existing model before running dbt build. What should the team expect?

    Checkpoint 9 of 9· Exam question

    By default, when a target relation for a selected model already exists in the destination schema, what does `dbt clone` do with that relation?

    Sources3

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.dbt clone always produces zero-copy clones of production tables.Why is that wrong?

      Zero-copy clones need both a warehouse that supports them (Snowflake, Databricks, BigQuery) and a table in the source environment. In every other case dbt creates a pointer view.

      Covered in What dbt clone creates in your target

    2. 2.Running dbt clone again refreshes every object that is already in the dev schema.Why is that wrong?

      Pre-existing relations are skipped by default. Only --full-refresh recreates them.

      Covered in What dbt clone creates in your target

    3. 3.dbt clone is the cheaper replacement for --defer.Why is that wrong?

      Clone uses compute and creates objects. Deferral is often cheaper and simpler, and clone is worth it only when real objects are needed, for example for a BI tool.

      Covered in When to clone and when to defer

    4. 4.Cloning incremental models in CI makes them run incrementally on any warehouse.Why is that wrong?

      The strategy depends on zero-copy cloning. On other warehouses the clone step creates pointer views instead.

      Covered in Cloning incremental models in slim CI

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “If your data platform supports zero-copy cloning of tables (Snowflake, Databricks, or BigQuery)”
      ↩︎ What dbt clone creates in your target
      “individual clone statements are independent of one another”
      ↩︎ What dbt clone creates in your target
      “Unlike deferral, dbt clone requires some compute and creation of additional objects in your data warehouse.”
      ↩︎ When to clone and when to defer
      “The dbt clone command in the dbt platform CLI automatically includes the --defer flag.”
      ↩︎ When to clone and when to defer
      “blue/green continuous deployment (on data warehouses that support zero-copy cloning tables)”
      ↩︎ When to clone and when to defer
      “The dbt clone command clones selected nodes from the specified state to the target schema(s).”
      ↩︎ Key concept
      “Otherwise, dbt will create a simple pointer view (select * from the source object)”
      ↩︎ Exam trap 1
      “By default, dbt clone will not recreate pre-existing relations in the current target. To override this, use the --full-refresh flag.”
      ↩︎ Exam trap 2
      “In many cases, deferral is a cheaper and simpler alternative to dbt clone.”
      ↩︎ Exam trap 3
      “Otherwise, dbt will create a simple pointer view (select * from the source object)”
      ↩︎ Checkpoint
      “By default, dbt clone will not recreate pre-existing relations in the current target. To override this, use the --full-refresh flag.”
      ↩︎ Checkpoint
      “dbt clone allows you to test out your code changes on downstream dependencies outside of dbt (such as a BI tool)”
      ↩︎ Checkpoint
      “Set up your Production environment and have a successful job run.”
      ↩︎ Checkpoint
    2. 2.
      “Mechanisms to support mature deployment at scale (dbt clone and dbt retry)”
      ↩︎ What dbt clone creates in your target
      “promoting specific models from a staging environment into production”
      ↩︎ When to clone and when to defer
    3. 3.
      “Typically incremental models are your largest datasets, so they take a long time to build in their entirety”
      ↩︎ Cloning incremental models in slim CI
      “it technically works without specifying state:old but adding state:old is more explicit”
      ↩︎ Cloning incremental models in slim CI
      “Our preference would be to have the failing CI job and have to manually override the blocking branch protection rule”
      ↩︎ Cloning incremental models in slim CI
      “This strategy only works for warehouse that support zero copy cloning (otherwise dbt clone will just create pointer views).”
      ↩︎ Exam trap 4
      “it does not yet exist in the PR-specific schema and is_incremental will be false”
      ↩︎ Prediction
      “An incremental build will fail.”
      ↩︎ Checkpoint

    Ready to test yourself?

    Practise the 11 questions on this subdomain.

    Spotted a mistake, or was something unclear? Tell us.