Define grants in dbt_project.yml at the project level under models: with grants: {select: ['role_name']} to apply a default GRANT SELECT to all materialized models; override at the model level with {{ config(grants={'select': ['reporting_role']}) }}
dbt applies GRANT statements after each model materializes; for table and incremental materializations this is after the full table is created or updated; for views dbt re-applies grants each run since views are recreated
Use {{ env_var('DBT_GRANT_ROLE') }} in the grants configuration to parameterize role names per environment, so dev grants differ from production grants without code changes
For incremental models on warehouses that recreate the table on --full-refresh, dbt re-grants after full refresh; verify that your grants configuration is idempotent and does not accumulate duplicate grants
Test that grants are applied correctly by querying the warehouse's information_schema.role_table_grants or equivalent after a dbt run and confirming the expected roles have SELECT on the materialized models
Known gotchas
Grants in dbt only manage SELECT (and optionally other DML) permissions; they do not manage schema-level or warehouse-level permissions, which must be provisioned separately by your DBA or infrastructure team
If a model fails to materialize, dbt does not apply the grants for that model; ensure that grant application failures (e.g., role does not exist) are surfaced as errors in your dbt run logs rather than being silently skipped
On Snowflake, GRANT to a role that does not yet exist raises an error; ensure all roles referenced in grants configuration are created before dbt run executes — missing roles in dev environments commonly cause CI failures that do not reproduce in production
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp