Configure GCP BigQuery Dataset Access

The gcp:bigquery/datasetAccess:DatasetAccess resource, part of the Pulumi GCP provider, grants access to a BigQuery dataset for users, service accounts, views, routines, or entire datasets. This guide focuses on three capabilities: service account and user grants, view and routine authorization, and cross-dataset access patterns.

Dataset access grants reference existing datasets, service accounts, views, or routines. The examples are intentionally small. Combine them with your own dataset infrastructure and identity management.

Grant a service account owner access

Automation workflows like ETL pipelines often need service accounts with administrative access to manage dataset contents and metadata.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const dataset = new gcp.bigquery.Dataset("dataset", {datasetId: "example_dataset"});
const bqowner = new gcp.serviceaccount.Account("bqowner", {accountId: "bqowner"});
const access = new gcp.bigquery.DatasetAccess("access", {
    datasetId: dataset.datasetId,
    role: "OWNER",
    userByEmail: bqowner.email,
});
import pulumi
import pulumi_gcp as gcp

dataset = gcp.bigquery.Dataset("dataset", dataset_id="example_dataset")
bqowner = gcp.serviceaccount.Account("bqowner", account_id="bqowner")
access = gcp.bigquery.DatasetAccess("access",
    dataset_id=dataset.dataset_id,
    role="OWNER",
    user_by_email=bqowner.email)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/bigquery"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/serviceaccount"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		dataset, err := bigquery.NewDataset(ctx, "dataset", &bigquery.DatasetArgs{
			DatasetId: pulumi.String("example_dataset"),
		})
		if err != nil {
			return err
		}
		bqowner, err := serviceaccount.NewAccount(ctx, "bqowner", &serviceaccount.AccountArgs{
			AccountId: pulumi.String("bqowner"),
		})
		if err != nil {
			return err
		}
		_, err = bigquery.NewDatasetAccess(ctx, "access", &bigquery.DatasetAccessArgs{
			DatasetId:   dataset.DatasetId,
			Role:        pulumi.String("OWNER"),
			UserByEmail: bqowner.Email,
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var dataset = new Gcp.BigQuery.Dataset("dataset", new()
    {
        DatasetId = "example_dataset",
    });

    var bqowner = new Gcp.ServiceAccount.Account("bqowner", new()
    {
        AccountId = "bqowner",
    });

    var access = new Gcp.BigQuery.DatasetAccess("access", new()
    {
        DatasetId = dataset.DatasetId,
        Role = "OWNER",
        UserByEmail = bqowner.Email,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.serviceaccount.Account;
import com.pulumi.gcp.serviceaccount.AccountArgs;
import com.pulumi.gcp.bigquery.DatasetAccess;
import com.pulumi.gcp.bigquery.DatasetAccessArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var dataset = new Dataset("dataset", DatasetArgs.builder()
            .datasetId("example_dataset")
            .build());

        var bqowner = new Account("bqowner", AccountArgs.builder()
            .accountId("bqowner")
            .build());

        var access = new DatasetAccess("access", DatasetAccessArgs.builder()
            .datasetId(dataset.datasetId())
            .role("OWNER")
            .userByEmail(bqowner.email())
            .build());

    }
}
resources:
  access:
    type: gcp:bigquery:DatasetAccess
    properties:
      datasetId: ${dataset.datasetId}
      role: OWNER
      userByEmail: ${bqowner.email}
  dataset:
    type: gcp:bigquery:Dataset
    properties:
      datasetId: example_dataset
  bqowner:
    type: gcp:serviceaccount:Account
    properties:
      accountId: bqowner

The role property sets the permission level (OWNER, READER, or WRITER). The userByEmail property identifies the service account receiving access. OWNER grants full control over the dataset, including the ability to delete it.

Share a view from another dataset

Data teams create views in public datasets that query private data, granting those views access to underlying tables without exposing raw data.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _private = new gcp.bigquery.Dataset("private", {datasetId: "example_dataset"});
const _public = new gcp.bigquery.Dataset("public", {datasetId: "example_dataset2"});
const publicTable = new gcp.bigquery.Table("public", {
    deletionProtection: false,
    datasetId: _public.datasetId,
    tableId: "example_table",
    view: {
        query: "SELECT state FROM [lookerdata:cdc.project_tycho_reports]",
        useLegacySql: false,
    },
});
const access = new gcp.bigquery.DatasetAccess("access", {
    datasetId: _private.datasetId,
    view: {
        projectId: publicTable.project,
        datasetId: _public.datasetId,
        tableId: publicTable.tableId,
    },
});
import pulumi
import pulumi_gcp as gcp

private = gcp.bigquery.Dataset("private", dataset_id="example_dataset")
public = gcp.bigquery.Dataset("public", dataset_id="example_dataset2")
public_table = gcp.bigquery.Table("public",
    deletion_protection=False,
    dataset_id=public.dataset_id,
    table_id="example_table",
    view={
        "query": "SELECT state FROM [lookerdata:cdc.project_tycho_reports]",
        "use_legacy_sql": False,
    })
access = gcp.bigquery.DatasetAccess("access",
    dataset_id=private.dataset_id,
    view={
        "project_id": public_table.project,
        "dataset_id": public.dataset_id,
        "table_id": public_table.table_id,
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/bigquery"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		private, err := bigquery.NewDataset(ctx, "private", &bigquery.DatasetArgs{
			DatasetId: pulumi.String("example_dataset"),
		})
		if err != nil {
			return err
		}
		public, err := bigquery.NewDataset(ctx, "public", &bigquery.DatasetArgs{
			DatasetId: pulumi.String("example_dataset2"),
		})
		if err != nil {
			return err
		}
		publicTable, err := bigquery.NewTable(ctx, "public", &bigquery.TableArgs{
			DeletionProtection: pulumi.Bool(false),
			DatasetId:          public.DatasetId,
			TableId:            pulumi.String("example_table"),
			View: &bigquery.TableViewArgs{
				Query:        pulumi.String("SELECT state FROM [lookerdata:cdc.project_tycho_reports]"),
				UseLegacySql: pulumi.Bool(false),
			},
		})
		if err != nil {
			return err
		}
		_, err = bigquery.NewDatasetAccess(ctx, "access", &bigquery.DatasetAccessArgs{
			DatasetId: private.DatasetId,
			View: &bigquery.DatasetAccessViewArgs{
				ProjectId: publicTable.Project,
				DatasetId: public.DatasetId,
				TableId:   publicTable.TableId,
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var @private = new Gcp.BigQuery.Dataset("private", new()
    {
        DatasetId = "example_dataset",
    });

    var @public = new Gcp.BigQuery.Dataset("public", new()
    {
        DatasetId = "example_dataset2",
    });

    var publicTable = new Gcp.BigQuery.Table("public", new()
    {
        DeletionProtection = false,
        DatasetId = @public.DatasetId,
        TableId = "example_table",
        View = new Gcp.BigQuery.Inputs.TableViewArgs
        {
            Query = "SELECT state FROM [lookerdata:cdc.project_tycho_reports]",
            UseLegacySql = false,
        },
    });

    var access = new Gcp.BigQuery.DatasetAccess("access", new()
    {
        DatasetId = @private.DatasetId,
        View = new Gcp.BigQuery.Inputs.DatasetAccessViewArgs
        {
            ProjectId = publicTable.Project,
            DatasetId = @public.DatasetId,
            TableId = publicTable.TableId,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.bigquery.Table;
import com.pulumi.gcp.bigquery.TableArgs;
import com.pulumi.gcp.bigquery.inputs.TableViewArgs;
import com.pulumi.gcp.bigquery.DatasetAccess;
import com.pulumi.gcp.bigquery.DatasetAccessArgs;
import com.pulumi.gcp.bigquery.inputs.DatasetAccessViewArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var private_ = new Dataset("private", DatasetArgs.builder()
            .datasetId("example_dataset")
            .build());

        var public_ = new Dataset("public", DatasetArgs.builder()
            .datasetId("example_dataset2")
            .build());

        var publicTable = new Table("publicTable", TableArgs.builder()
            .deletionProtection(false)
            .datasetId(public_.datasetId())
            .tableId("example_table")
            .view(TableViewArgs.builder()
                .query("SELECT state FROM [lookerdata:cdc.project_tycho_reports]")
                .useLegacySql(false)
                .build())
            .build());

        var access = new DatasetAccess("access", DatasetAccessArgs.builder()
            .datasetId(private_.datasetId())
            .view(DatasetAccessViewArgs.builder()
                .projectId(publicTable.project())
                .datasetId(public_.datasetId())
                .tableId(publicTable.tableId())
                .build())
            .build());

    }
}
resources:
  access:
    type: gcp:bigquery:DatasetAccess
    properties:
      datasetId: ${private.datasetId}
      view:
        projectId: ${publicTable.project}
        datasetId: ${public.datasetId}
        tableId: ${publicTable.tableId}
  private:
    type: gcp:bigquery:Dataset
    properties:
      datasetId: example_dataset
  public:
    type: gcp:bigquery:Dataset
    properties:
      datasetId: example_dataset2
  publicTable:
    type: gcp:bigquery:Table
    name: public
    properties:
      deletionProtection: false
      datasetId: ${public.datasetId}
      tableId: example_table
      view:
        query: SELECT state FROM [lookerdata:cdc.project_tycho_reports]
        useLegacySql: false

The view property grants a specific view access to query tables in this dataset. Queries executed against that view can read tables here, but direct table access remains restricted. The role property is not required when granting view access.

Authorize all views in another dataset

Organizations with multiple datasets can grant all views in one dataset access to tables in another, enabling cross-dataset analytics without per-view configuration.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _private = new gcp.bigquery.Dataset("private", {datasetId: "private"});
const _public = new gcp.bigquery.Dataset("public", {datasetId: "public"});
const access = new gcp.bigquery.DatasetAccess("access", {
    datasetId: _private.datasetId,
    authorizedDataset: {
        dataset: {
            projectId: _public.project,
            datasetId: _public.datasetId,
        },
        targetTypes: ["VIEWS"],
    },
});
import pulumi
import pulumi_gcp as gcp

private = gcp.bigquery.Dataset("private", dataset_id="private")
public = gcp.bigquery.Dataset("public", dataset_id="public")
access = gcp.bigquery.DatasetAccess("access",
    dataset_id=private.dataset_id,
    authorized_dataset={
        "dataset": {
            "project_id": public.project,
            "dataset_id": public.dataset_id,
        },
        "target_types": ["VIEWS"],
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/bigquery"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		private, err := bigquery.NewDataset(ctx, "private", &bigquery.DatasetArgs{
			DatasetId: pulumi.String("private"),
		})
		if err != nil {
			return err
		}
		public, err := bigquery.NewDataset(ctx, "public", &bigquery.DatasetArgs{
			DatasetId: pulumi.String("public"),
		})
		if err != nil {
			return err
		}
		_, err = bigquery.NewDatasetAccess(ctx, "access", &bigquery.DatasetAccessArgs{
			DatasetId: private.DatasetId,
			AuthorizedDataset: &bigquery.DatasetAccessAuthorizedDatasetArgs{
				Dataset: &bigquery.DatasetAccessAuthorizedDatasetDatasetArgs{
					ProjectId: public.Project,
					DatasetId: public.DatasetId,
				},
				TargetTypes: pulumi.StringArray{
					pulumi.String("VIEWS"),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var @private = new Gcp.BigQuery.Dataset("private", new()
    {
        DatasetId = "private",
    });

    var @public = new Gcp.BigQuery.Dataset("public", new()
    {
        DatasetId = "public",
    });

    var access = new Gcp.BigQuery.DatasetAccess("access", new()
    {
        DatasetId = @private.DatasetId,
        AuthorizedDataset = new Gcp.BigQuery.Inputs.DatasetAccessAuthorizedDatasetArgs
        {
            Dataset = new Gcp.BigQuery.Inputs.DatasetAccessAuthorizedDatasetDatasetArgs
            {
                ProjectId = @public.Project,
                DatasetId = @public.DatasetId,
            },
            TargetTypes = new[]
            {
                "VIEWS",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.bigquery.DatasetAccess;
import com.pulumi.gcp.bigquery.DatasetAccessArgs;
import com.pulumi.gcp.bigquery.inputs.DatasetAccessAuthorizedDatasetArgs;
import com.pulumi.gcp.bigquery.inputs.DatasetAccessAuthorizedDatasetDatasetArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var private_ = new Dataset("private", DatasetArgs.builder()
            .datasetId("private")
            .build());

        var public_ = new Dataset("public", DatasetArgs.builder()
            .datasetId("public")
            .build());

        var access = new DatasetAccess("access", DatasetAccessArgs.builder()
            .datasetId(private_.datasetId())
            .authorizedDataset(DatasetAccessAuthorizedDatasetArgs.builder()
                .dataset(DatasetAccessAuthorizedDatasetDatasetArgs.builder()
                    .projectId(public_.project())
                    .datasetId(public_.datasetId())
                    .build())
                .targetTypes("VIEWS")
                .build())
            .build());

    }
}
resources:
  access:
    type: gcp:bigquery:DatasetAccess
    properties:
      datasetId: ${private.datasetId}
      authorizedDataset:
        dataset:
          projectId: ${public.project}
          datasetId: ${public.datasetId}
        targetTypes:
          - VIEWS
  private:
    type: gcp:bigquery:Dataset
    properties:
      datasetId: private
  public:
    type: gcp:bigquery:Dataset
    properties:
      datasetId: public

The authorizedDataset property grants all resources of specified types in another dataset read access. The targetTypes property limits which resource types are authorized; here, only VIEWS can query this dataset’s tables.

Authorize a routine from another dataset

User-defined functions and stored procedures in one dataset may need to query tables in another dataset.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _public = new gcp.bigquery.Dataset("public", {
    datasetId: "public_dataset",
    description: "This dataset is public",
});
const publicRoutine = new gcp.bigquery.Routine("public", {
    datasetId: _public.datasetId,
    routineId: "public_routine",
    routineType: "TABLE_VALUED_FUNCTION",
    language: "SQL",
    definitionBody: "SELECT 1 + value AS value\n",
    arguments: [{
        name: "value",
        argumentKind: "FIXED_TYPE",
        dataType: JSON.stringify({
            typeKind: "INT64",
        }),
    }],
    returnTableType: JSON.stringify({
        columns: [{
            name: "value",
            type: {
                typeKind: "INT64",
            },
        }],
    }),
});
const _private = new gcp.bigquery.Dataset("private", {
    datasetId: "private_dataset",
    description: "This dataset is private",
});
const authorizedRoutine = new gcp.bigquery.DatasetAccess("authorized_routine", {
    datasetId: _private.datasetId,
    routine: {
        projectId: publicRoutine.project,
        datasetId: publicRoutine.datasetId,
        routineId: publicRoutine.routineId,
    },
});
import pulumi
import json
import pulumi_gcp as gcp

public = gcp.bigquery.Dataset("public",
    dataset_id="public_dataset",
    description="This dataset is public")
public_routine = gcp.bigquery.Routine("public",
    dataset_id=public.dataset_id,
    routine_id="public_routine",
    routine_type="TABLE_VALUED_FUNCTION",
    language="SQL",
    definition_body="SELECT 1 + value AS value\n",
    arguments=[{
        "name": "value",
        "argument_kind": "FIXED_TYPE",
        "data_type": json.dumps({
            "typeKind": "INT64",
        }),
    }],
    return_table_type=json.dumps({
        "columns": [{
            "name": "value",
            "type": {
                "typeKind": "INT64",
            },
        }],
    }))
private = gcp.bigquery.Dataset("private",
    dataset_id="private_dataset",
    description="This dataset is private")
authorized_routine = gcp.bigquery.DatasetAccess("authorized_routine",
    dataset_id=private.dataset_id,
    routine={
        "project_id": public_routine.project,
        "dataset_id": public_routine.dataset_id,
        "routine_id": public_routine.routine_id,
    })
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/bigquery"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		public, err := bigquery.NewDataset(ctx, "public", &bigquery.DatasetArgs{
			DatasetId:   pulumi.String("public_dataset"),
			Description: pulumi.String("This dataset is public"),
		})
		if err != nil {
			return err
		}
		tmpJSON0, err := json.Marshal(map[string]interface{}{
			"typeKind": "INT64",
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		tmpJSON1, err := json.Marshal(map[string]interface{}{
			"columns": []map[string]interface{}{
				map[string]interface{}{
					"name": "value",
					"type": map[string]interface{}{
						"typeKind": "INT64",
					},
				},
			},
		})
		if err != nil {
			return err
		}
		json1 := string(tmpJSON1)
		publicRoutine, err := bigquery.NewRoutine(ctx, "public", &bigquery.RoutineArgs{
			DatasetId:      public.DatasetId,
			RoutineId:      pulumi.String("public_routine"),
			RoutineType:    pulumi.String("TABLE_VALUED_FUNCTION"),
			Language:       pulumi.String("SQL"),
			DefinitionBody: pulumi.String("SELECT 1 + value AS value\n"),
			Arguments: bigquery.RoutineArgumentArray{
				&bigquery.RoutineArgumentArgs{
					Name:         pulumi.String("value"),
					ArgumentKind: pulumi.String("FIXED_TYPE"),
					DataType:     pulumi.String(json0),
				},
			},
			ReturnTableType: pulumi.String(json1),
		})
		if err != nil {
			return err
		}
		private, err := bigquery.NewDataset(ctx, "private", &bigquery.DatasetArgs{
			DatasetId:   pulumi.String("private_dataset"),
			Description: pulumi.String("This dataset is private"),
		})
		if err != nil {
			return err
		}
		_, err = bigquery.NewDatasetAccess(ctx, "authorized_routine", &bigquery.DatasetAccessArgs{
			DatasetId: private.DatasetId,
			Routine: &bigquery.DatasetAccessRoutineArgs{
				ProjectId: publicRoutine.Project,
				DatasetId: publicRoutine.DatasetId,
				RoutineId: publicRoutine.RoutineId,
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var @public = new Gcp.BigQuery.Dataset("public", new()
    {
        DatasetId = "public_dataset",
        Description = "This dataset is public",
    });

    var publicRoutine = new Gcp.BigQuery.Routine("public", new()
    {
        DatasetId = @public.DatasetId,
        RoutineId = "public_routine",
        RoutineType = "TABLE_VALUED_FUNCTION",
        Language = "SQL",
        DefinitionBody = @"SELECT 1 + value AS value
",
        Arguments = new[]
        {
            new Gcp.BigQuery.Inputs.RoutineArgumentArgs
            {
                Name = "value",
                ArgumentKind = "FIXED_TYPE",
                DataType = JsonSerializer.Serialize(new Dictionary<string, object?>
                {
                    ["typeKind"] = "INT64",
                }),
            },
        },
        ReturnTableType = JsonSerializer.Serialize(new Dictionary<string, object?>
        {
            ["columns"] = new[]
            {
                new Dictionary<string, object?>
                {
                    ["name"] = "value",
                    ["type"] = new Dictionary<string, object?>
                    {
                        ["typeKind"] = "INT64",
                    },
                },
            },
        }),
    });

    var @private = new Gcp.BigQuery.Dataset("private", new()
    {
        DatasetId = "private_dataset",
        Description = "This dataset is private",
    });

    var authorizedRoutine = new Gcp.BigQuery.DatasetAccess("authorized_routine", new()
    {
        DatasetId = @private.DatasetId,
        Routine = new Gcp.BigQuery.Inputs.DatasetAccessRoutineArgs
        {
            ProjectId = publicRoutine.Project,
            DatasetId = publicRoutine.DatasetId,
            RoutineId = publicRoutine.RoutineId,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.bigquery.Routine;
import com.pulumi.gcp.bigquery.RoutineArgs;
import com.pulumi.gcp.bigquery.inputs.RoutineArgumentArgs;
import com.pulumi.gcp.bigquery.DatasetAccess;
import com.pulumi.gcp.bigquery.DatasetAccessArgs;
import com.pulumi.gcp.bigquery.inputs.DatasetAccessRoutineArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var public_ = new Dataset("public", DatasetArgs.builder()
            .datasetId("public_dataset")
            .description("This dataset is public")
            .build());

        var publicRoutine = new Routine("publicRoutine", RoutineArgs.builder()
            .datasetId(public_.datasetId())
            .routineId("public_routine")
            .routineType("TABLE_VALUED_FUNCTION")
            .language("SQL")
            .definitionBody("""
SELECT 1 + value AS value
            """)
            .arguments(RoutineArgumentArgs.builder()
                .name("value")
                .argumentKind("FIXED_TYPE")
                .dataType(serializeJson(
                    jsonObject(
                        jsonProperty("typeKind", "INT64")
                    )))
                .build())
            .returnTableType(serializeJson(
                jsonObject(
                    jsonProperty("columns", jsonArray(jsonObject(
                        jsonProperty("name", "value"),
                        jsonProperty("type", jsonObject(
                            jsonProperty("typeKind", "INT64")
                        ))
                    )))
                )))
            .build());

        var private_ = new Dataset("private", DatasetArgs.builder()
            .datasetId("private_dataset")
            .description("This dataset is private")
            .build());

        var authorizedRoutine = new DatasetAccess("authorizedRoutine", DatasetAccessArgs.builder()
            .datasetId(private_.datasetId())
            .routine(DatasetAccessRoutineArgs.builder()
                .projectId(publicRoutine.project())
                .datasetId(publicRoutine.datasetId())
                .routineId(publicRoutine.routineId())
                .build())
            .build());

    }
}
resources:
  public:
    type: gcp:bigquery:Dataset
    properties:
      datasetId: public_dataset
      description: This dataset is public
  publicRoutine:
    type: gcp:bigquery:Routine
    name: public
    properties:
      datasetId: ${public.datasetId}
      routineId: public_routine
      routineType: TABLE_VALUED_FUNCTION
      language: SQL
      definitionBody: |
        SELECT 1 + value AS value        
      arguments:
        - name: value
          argumentKind: FIXED_TYPE
          dataType:
            fn::toJSON:
              typeKind: INT64
      returnTableType:
        fn::toJSON:
          columns:
            - name: value
              type:
                typeKind: INT64
  private:
    type: gcp:bigquery:Dataset
    properties:
      datasetId: private_dataset
      description: This dataset is private
  authorizedRoutine:
    type: gcp:bigquery:DatasetAccess
    name: authorized_routine
    properties:
      datasetId: ${private.datasetId}
      routine:
        projectId: ${publicRoutine.project}
        datasetId: ${publicRoutine.datasetId}
        routineId: ${publicRoutine.routineId}

The routine property grants a specific UDF or stored procedure access to query tables in this dataset. Like views, routines don’t require a role property. If the routine is updated, you must re-grant access via an update operation.

Beyond these examples

These snippets focus on specific dataset access features: user and service account grants, view and routine authorization, and cross-dataset access patterns. They’re intentionally minimal rather than full data governance solutions.

The examples reference pre-existing infrastructure such as BigQuery datasets and service accounts, views, or routines being granted access. They focus on configuring access grants rather than provisioning the underlying resources.

To keep things focused, common access patterns are omitted, including:

  • Group and domain-based access (groupByEmail, domain)
  • Special groups (projectOwners, allAuthenticatedUsers)
  • Conditional access with CEL expressions (condition)
  • Generic IAM members (iamMember)

These omissions are intentional: the goal is to illustrate how each access pattern is wired, not provide drop-in governance modules. See the BigQuery DatasetAccess resource reference for all available configuration options.

Let's configure GCP BigQuery Dataset Access

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Access Configuration & Types
What types of access can I grant to a BigQuery dataset?
You can grant access using userByEmail, groupByEmail, domain, iamMember, specialGroup, view, routine, or authorizedDataset. Each type grants different levels of access to different entities.
Do I need to specify a role when granting view or routine access?
No, the role field is not required when view or routine is set. These access types grant read access automatically.
What special groups can I use for dataset access?
You can use projectOwners, projectReaders, projectWriters, or allAuthenticatedUsers with the specialGroup property.
Common Issues & Limitations
Why am I seeing a perpetual diff after creating dataset access with a predefined role?
Predefined roles with equivalent basic roles are swapped by the API to their basic counterparts, causing a diff post-create. Use basic roles directly to avoid this issue.
Can I import existing BigQuery dataset access into Pulumi?
No, this resource does not support import. You must create new DatasetAccess resources instead of importing existing ones.
Why did my iamMember value change after creation?
The API may translate iamMember to a different member type. Check the apiUpdatedMember output property to detect when this translation occurs.
Can I modify dataset access after creation?
No, all properties are immutable. Any change to datasetId, project, or access configuration properties forces resource replacement.
View & Routine Access
What happens if I update a view or routine that has dataset access?
If a view or routine is updated by any user, access to it needs to be granted again via an update operation. Re-apply the DatasetAccess resource after updating the view or routine.
What access does a view or routine grant to the dataset?
Queries executed against the view or routine will have read access to tables in the dataset. This allows controlled access without granting direct table permissions.

Using a different cloud?

Explore analytics guides for other cloud providers: