BigQuery provides several mechanisms for sharing data across organizational boundaries, each suited to different trust models and data sensitivity requirements. This note covers the agency/client pattern, Analytics Hub, authorized views, and row/column-level security.
Agency/Client Pattern: Work in Client Organizations
The recommended pattern for agencies and consultancies: each client owns their GCP organization. The agency gets access as needed.
Client Alpha Organization (owned by client)├── client-alpha-analytics│ └── All BigQuery resources, dbt models, data└── IAM: Agency team granted access
Client Beta Organization (owned by client)├── client-beta-analytics│ └── All BigQuery resources, dbt models, data└── IAM: Agency team granted access
Agency Organization (agency-owned)└── agency-internal └── Internal tooling, templates, documentation onlyThis provides clear data ownership. Client data stays in client infrastructure. When engagements end, clients retain full control without data migration. Billing flows naturally to client accounts. Compliance requirements are the client’s responsibility to define and the agency’s responsibility to follow.
The agency team authenticates to each client organization separately. Maintain separate service accounts per client, separate credentials, separate dbt profiles. This adds overhead but prevents cross-client data leakage and keeps audit trails clean.
Fallback: Project-per-Client in Agency Organization
Some clients can’t or won’t maintain their own GCP organization — small businesses without IT infrastructure, short-term engagements, or clients who explicitly want the agency to handle everything.
Agency Organization├── agency-admin│ └── Audit logs, billing exports, shared tooling├── client-alpha-analytics│ └── All BigQuery resources for Client Alpha└── client-beta-analytics └── All BigQuery resources for Client BetaThis pattern requires extra care. Document clearly that the agency owns the infrastructure. Define data ownership and export rights in contracts. Plan for offboarding: if a client wants to leave, you’ll need to export their data and potentially migrate their dbt project to their own organization.
Use labels and separate projects to track costs accurately per client. Billing can flow to the client’s billing account (linked to the agency project) or the agency can invoice based on costs.
Analytics Hub for Formal Data Sharing
Analytics Hub enables zero-copy data sharing across organizational boundaries. It’s the right tool when you need structured, auditable sharing with clear publisher/subscriber roles.
A data owner publishes a dataset to an Analytics Hub listing. Subscribers in other organizations request access. Once approved, they get a linked dataset — a read-only reference that points to the source data without copying it.
Key characteristics:
- Storage costs stay with the publisher. Query costs go to the subscriber.
- Subscribers cannot modify data, cannot set IAM on individual tables, cannot do anything except read.
- Publishers can restrict data egress entirely, blocking
EXPORT,CREATE TABLE AS SELECT, and copy operations. - All access is logged for auditing.
For agency work, create a private exchange within Analytics Hub. Add specific principals (users, groups, or service accounts) as subscribers. Clients subscribe to listings and query through their linked datasets.
Analytics Hub is particularly useful when the data relationship is truly one-directional: a data provider shares curated datasets with consumers who should only read, never modify. For bidirectional collaboration (where both parties create and share data), the separate-organization patterns above are more appropriate.
Authorized Views for Controlled Access
Authorized views solve a common problem: exposing filtered or aggregated data without granting access to underlying tables. They work across organizational boundaries.
The pattern:
- Create a view in a dedicated dataset that queries sensitive source tables
- Authorize the view’s dataset to access the source dataset
- Grant users access to the view dataset only
-- In dataset: shared_viewsCREATE VIEW shared_views.analyst_orders ASSELECT order_id, order_date, total_amount -- customer_ssn excluded -- internal_notes excludedFROM sensitive_data.mrt__sales__ordersWHERE region = 'EMEA'; -- Row filteringThe view references sensitive_data.mrt__sales__orders, but users only need access to shared_views. In BigQuery’s console, you authorize shared_views to access sensitive_data. Anyone who can query shared_views.analyst_orders gets the filtered, column-restricted view without any permissions on sensitive_data.
Authorized datasets extend this concept. Instead of authorizing individual views, you authorize an entire dataset. All current and future views in that dataset can access the source data. This reduces management overhead when you’re creating many views for different access patterns.
Authorized views are the simplest mechanism for column-filtering and row-filtering use cases. They don’t require Analytics Hub infrastructure and work within a single project or across projects.
Row-Level and Column-Level Security
For truly multi-tenant environments where different users see different rows of the same table, BigQuery offers row-level security:
CREATE ROW ACCESS POLICY client_a_onlyON multi_tenant.mrt__shared__ordersGRANT TO ('group:client-a-analysts@clienta.com')FILTER USING (client_id = 'CLIENT_A');
CREATE ROW ACCESS POLICY client_b_onlyON multi_tenant.mrt__shared__ordersGRANT TO ('group:client-b-analysts@clientb.com')FILTER USING (client_id = 'CLIENT_B');Client A analysts querying multi_tenant.mrt__shared__orders see only their rows. Client B sees only theirs. The table is the same; the access differs. This is transparent to the query — users don’t need to add WHERE client_id = ... clauses, and they can’t bypass the filter even if they try.
Column-level security uses Data Catalog policy tags. You create a tag (say, PII), apply it to sensitive columns, then grant specific users the Fine-Grained Reader role for that tag. Users without the role see those columns as null or receive access errors.
Dynamic data masking takes this further. Users with Masked Reader role see hashed or partially redacted values instead of nulls. Useful for scenarios where analysts need to see that a value exists and can join on it, but shouldn’t see the actual content — think hashed email addresses for matching across datasets without exposing PII.
Choosing the Right Mechanism
| Mechanism | Best for | Complexity | Cross-org? |
|---|---|---|---|
| Authorized views | Column/row filtering within projects | Low | Yes |
| Authorized datasets | Many views needing source access | Low | Yes |
| Analytics Hub | Formal publisher/subscriber sharing | Medium | Yes |
| Row-level security | Multi-tenant same-table access | Medium | Yes |
| Column-level security | PII protection across consumers | Medium | Yes |
| Separate projects | Full isolation per client/team | High | N/A |
Start with the simplest mechanism that meets your requirements. Authorized views handle most cases. Row-level security adds value when you can’t separate tenants into different datasets. Analytics Hub adds value when you need formal governance over who can subscribe to what.