feat(bigquery): support row_access_policy config for BigQuery tables #2221
Description
Feature request
Description
The row_access_policy field exists in dbt-core's model config JSON schema and is implemented by the Snowflake and Databricks adapters, but the BigQuery adapter does not support it.
BigQuery supports Row-Level Security via CREATE ROW ACCESS POLICY, which allows filtering rows based on the querying principal (SESSION_USER()). This is useful for data governance scenarios such as consent-based filtering, multi-tenant isolation, and role-based access control.
The problem
BigQuery drops row access policies when a table is rebuilt via CREATE OR REPLACE TABLE — which is what dbt does for materialized='table' and materialized='incremental' with --full-refresh. This makes it impossible to maintain RLS policies declaratively through dbt.
The BigQuery adapter already solves an analogous problem for column-level security: policy_tags are re-applied after every table build via persist_docs → _update_column_dict. Row access policies need the same treatment.
Proposed solution
Add a row_access_policy config key to the BigQuery adapter that:
- Accepts a dict with
filter_using(SQL predicate),grantees(list of principals), and an optionalpolicy_name - After every table/incremental/view materialization, drops the dbt-managed policy (by name) and re-creates it
- Follows the same lifecycle as
policy_tags— declarative config, re-applied after every build
Example usage
{{ config(
materialized='table',
row_access_policy={
'filter_using': 'org_id NOT IN (SELECT org_id FROM `project.dataset.optouts`)',
'grantees': ['serviceAccount:ai-bot@project.iam.gserviceaccount.com'],
'policy_name': 'consent_filter',
}
) }}Who would benefit
Teams using BigQuery's native RLS for data governance. Currently the only workaround is maintaining separate filtered views (governed facades), which is error-prone and doesn't scale.
Activity
Use targeted policy drop, add view materialization support, link issue