Overview
Some dbt™ projects build on top of data that arrives through Snowflake Secure Data Sharing, for example when an upstream team shares its models from a separate Snowflake account. If your Turbo CI commands usedbt clone to copy production relations into the temporary CI schema, any relation that lives in a shared database fails to clone:
Why a macro override is needed
Three things combine to cause this failure, and only the last one is fixable in your project:- Snowflake cannot clone shared objects. Zero-copy cloning works by referencing a table’s underlying storage metadata, which stays in the provider’s account. A shared database is a read-only window into that account, so there is nothing to clone from. This is a platform limit with no workaround, and no
GRANTchanges it. - dbt™ has the right fallback, but never uses it on Snowflake. The clone materialization already knows how to create a view over the production relation instead of a clone. It picks between the two up front by asking the adapter
can_clone_table(), and the Snowflake adapter answerstrueunconditionally. The check means “does this warehouse support CLONE at all”, not “can this specific relation be cloned”, and dbt™ does not catch the error and retry as a view. The result is that the fallback exists but the routing to it never fires. - The routing is overridable.
dbt clonebuilds its SQL through dispatched macros, so a project-levelsnowflake__create_or_replace_clonecan make the clone-or-view decision per relation instead of per adapter.
Configure the macro override
1. Add the macro
In your dbt™ project’s macros folder, createcreate_or_replace_clone.sql:
create_or_replace_clone.sql
2. Register the override
Indbt_project.yml, add a dispatch config so dbt™ finds your macro before its built-in one. Replace my_project with the name defined at the top of your dbt_project.yml:
dbt_project.yml
If your project already has a
dispatch block, for example for dbt_utils, add the macro_namespace: dbt entry to it instead of creating a second block.3. List your shared databases
Also indbt_project.yml, list every database that is imported through a share. Matching is case-insensitive:
dbt_project.yml
Usage
The macro only changes whatdbt clone executes, not how you configure Turbo CI. Make sure your Turbo CI schedule has deferral enabled by setting deferred_schedule_slug to your production schedule. Paradime supplies the production manifest to every command in the schedule, so you do not pass --state or --defer flags yourself:
Requirements and limitations
- Permissions: the warehouse user in your
cienvironment needsIMPORTED PRIVILEGESon each shared database. If it can alreadyselectfrom the share, no extra grant is needed. - Views read live data, not a snapshot: a clone freezes data at the moment it is created, while a view always shows the share’s current state. If the provider refreshes the shared data during or between CI runs, queries against the view reflect the new data. This is usually fine for CI, but results are not point-in-time reproducible the way clones are.
- Upstream schema changes: Snowflake expands
select *when the view is created. If the provider adds, removes, or renames columns in a shared table, existing views can fail or return an outdated column set. Re-rundbt clonewith--full-refreshto recreate them. - Re-runs:
dbt cloneskips relations that already exist in the target schema. Pass--full-refreshwhen you want them recreated, for example while testing this setup. - Changed incremental models: a view is not a writable base. An incremental model that is itself modified in a pull request and whose production relation lives in a shared database builds from scratch in the CI schema. For very large models, add a row-limit filter for the
citarget. - dbt™ versions: requires dbt™ 1.6 or later, when
dbt clonewas introduced. The macro shadows the adapter’s default implementation, so compare it against the default again after majordbt-snowflakeupgrades.