Create GCP BigQuery Analytics Hub Listings

The gcp:bigqueryanalyticshub/listing:Listing resource, part of the Pulumi GCP provider, defines an Analytics Hub listing that makes BigQuery datasets or Pub/Sub topics available for subscription. This guide focuses on three capabilities: dataset and streaming data sharing, export restrictions and query logging, and DCR table selection and public discovery.

Listings belong to DataExchange resources and reference BigQuery datasets, tables, or Pub/Sub topics that must exist separately. The examples are intentionally small. Combine them with your own data exchanges, datasets, and access policies.

Share a BigQuery dataset through Analytics Hub

Data teams publish datasets to Analytics Hub to make them discoverable and shareable across organizations.

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

const listing = new gcp.bigqueryanalyticshub.DataExchange("listing", {
    location: "US",
    dataExchangeId: "my_data_exchange",
    displayName: "my_data_exchange",
    description: "example data exchange",
});
const listingDataset = new gcp.bigquery.Dataset("listing", {
    datasetId: "my_listing",
    friendlyName: "my_listing",
    description: "example data exchange",
    location: "US",
});
const listingListing = new gcp.bigqueryanalyticshub.Listing("listing", {
    location: "US",
    dataExchangeId: listing.dataExchangeId,
    listingId: "my_listing",
    displayName: "my_listing",
    description: "example data exchange",
    bigqueryDataset: {
        dataset: listingDataset.id,
    },
});
import pulumi
import pulumi_gcp as gcp

listing = gcp.bigqueryanalyticshub.DataExchange("listing",
    location="US",
    data_exchange_id="my_data_exchange",
    display_name="my_data_exchange",
    description="example data exchange")
listing_dataset = gcp.bigquery.Dataset("listing",
    dataset_id="my_listing",
    friendly_name="my_listing",
    description="example data exchange",
    location="US")
listing_listing = gcp.bigqueryanalyticshub.Listing("listing",
    location="US",
    data_exchange_id=listing.data_exchange_id,
    listing_id="my_listing",
    display_name="my_listing",
    description="example data exchange",
    bigquery_dataset={
        "dataset": listing_dataset.id,
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		listing, err := bigqueryanalyticshub.NewDataExchange(ctx, "listing", &bigqueryanalyticshub.DataExchangeArgs{
			Location:       pulumi.String("US"),
			DataExchangeId: pulumi.String("my_data_exchange"),
			DisplayName:    pulumi.String("my_data_exchange"),
			Description:    pulumi.String("example data exchange"),
		})
		if err != nil {
			return err
		}
		listingDataset, err := bigquery.NewDataset(ctx, "listing", &bigquery.DatasetArgs{
			DatasetId:    pulumi.String("my_listing"),
			FriendlyName: pulumi.String("my_listing"),
			Description:  pulumi.String("example data exchange"),
			Location:     pulumi.String("US"),
		})
		if err != nil {
			return err
		}
		_, err = bigqueryanalyticshub.NewListing(ctx, "listing", &bigqueryanalyticshub.ListingArgs{
			Location:       pulumi.String("US"),
			DataExchangeId: listing.DataExchangeId,
			ListingId:      pulumi.String("my_listing"),
			DisplayName:    pulumi.String("my_listing"),
			Description:    pulumi.String("example data exchange"),
			BigqueryDataset: &bigqueryanalyticshub.ListingBigqueryDatasetArgs{
				Dataset: listingDataset.ID(),
			},
		})
		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 listing = new Gcp.BigQueryAnalyticsHub.DataExchange("listing", new()
    {
        Location = "US",
        DataExchangeId = "my_data_exchange",
        DisplayName = "my_data_exchange",
        Description = "example data exchange",
    });

    var listingDataset = new Gcp.BigQuery.Dataset("listing", new()
    {
        DatasetId = "my_listing",
        FriendlyName = "my_listing",
        Description = "example data exchange",
        Location = "US",
    });

    var listingListing = new Gcp.BigQueryAnalyticsHub.Listing("listing", new()
    {
        Location = "US",
        DataExchangeId = listing.DataExchangeId,
        ListingId = "my_listing",
        DisplayName = "my_listing",
        Description = "example data exchange",
        BigqueryDataset = new Gcp.BigQueryAnalyticsHub.Inputs.ListingBigqueryDatasetArgs
        {
            Dataset = listingDataset.Id,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigqueryanalyticshub.DataExchange;
import com.pulumi.gcp.bigqueryanalyticshub.DataExchangeArgs;
import com.pulumi.gcp.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.bigqueryanalyticshub.Listing;
import com.pulumi.gcp.bigqueryanalyticshub.ListingArgs;
import com.pulumi.gcp.bigqueryanalyticshub.inputs.ListingBigqueryDatasetArgs;
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 listing = new DataExchange("listing", DataExchangeArgs.builder()
            .location("US")
            .dataExchangeId("my_data_exchange")
            .displayName("my_data_exchange")
            .description("example data exchange")
            .build());

        var listingDataset = new Dataset("listingDataset", DatasetArgs.builder()
            .datasetId("my_listing")
            .friendlyName("my_listing")
            .description("example data exchange")
            .location("US")
            .build());

        var listingListing = new Listing("listingListing", ListingArgs.builder()
            .location("US")
            .dataExchangeId(listing.dataExchangeId())
            .listingId("my_listing")
            .displayName("my_listing")
            .description("example data exchange")
            .bigqueryDataset(ListingBigqueryDatasetArgs.builder()
                .dataset(listingDataset.id())
                .build())
            .build());

    }
}
resources:
  listing:
    type: gcp:bigqueryanalyticshub:DataExchange
    properties:
      location: US
      dataExchangeId: my_data_exchange
      displayName: my_data_exchange
      description: example data exchange
  listingListing:
    type: gcp:bigqueryanalyticshub:Listing
    name: listing
    properties:
      location: US
      dataExchangeId: ${listing.dataExchangeId}
      listingId: my_listing
      displayName: my_listing
      description: example data exchange
      bigqueryDataset:
        dataset: ${listingDataset.id}
  listingDataset:
    type: gcp:bigquery:Dataset
    name: listing
    properties:
      datasetId: my_listing
      friendlyName: my_listing
      description: example data exchange
      location: US

The listing connects a BigQuery dataset to a data exchange through the bigqueryDataset property. The dataExchangeId ties the listing to its parent exchange, while the dataset property references the BigQuery dataset by ID. Subscribers can then discover and link to this dataset through the Analytics Hub interface.

Restrict data export and query results

Organizations sharing sensitive data often need to prevent subscribers from exporting the data or saving query results outside the Analytics Hub environment.

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

const listing = new gcp.bigqueryanalyticshub.DataExchange("listing", {
    location: "US",
    dataExchangeId: "my_data_exchange",
    displayName: "my_data_exchange",
    description: "example data exchange",
});
const listingDataset = new gcp.bigquery.Dataset("listing", {
    datasetId: "my_listing",
    friendlyName: "my_listing",
    description: "example data exchange",
    location: "US",
});
const listingListing = new gcp.bigqueryanalyticshub.Listing("listing", {
    location: "US",
    dataExchangeId: listing.dataExchangeId,
    listingId: "my_listing",
    displayName: "my_listing",
    description: "example data exchange",
    bigqueryDataset: {
        dataset: listingDataset.id,
    },
    restrictedExportConfig: {
        enabled: true,
        restrictQueryResult: true,
    },
});
import pulumi
import pulumi_gcp as gcp

listing = gcp.bigqueryanalyticshub.DataExchange("listing",
    location="US",
    data_exchange_id="my_data_exchange",
    display_name="my_data_exchange",
    description="example data exchange")
listing_dataset = gcp.bigquery.Dataset("listing",
    dataset_id="my_listing",
    friendly_name="my_listing",
    description="example data exchange",
    location="US")
listing_listing = gcp.bigqueryanalyticshub.Listing("listing",
    location="US",
    data_exchange_id=listing.data_exchange_id,
    listing_id="my_listing",
    display_name="my_listing",
    description="example data exchange",
    bigquery_dataset={
        "dataset": listing_dataset.id,
    },
    restricted_export_config={
        "enabled": True,
        "restrict_query_result": True,
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		listing, err := bigqueryanalyticshub.NewDataExchange(ctx, "listing", &bigqueryanalyticshub.DataExchangeArgs{
			Location:       pulumi.String("US"),
			DataExchangeId: pulumi.String("my_data_exchange"),
			DisplayName:    pulumi.String("my_data_exchange"),
			Description:    pulumi.String("example data exchange"),
		})
		if err != nil {
			return err
		}
		listingDataset, err := bigquery.NewDataset(ctx, "listing", &bigquery.DatasetArgs{
			DatasetId:    pulumi.String("my_listing"),
			FriendlyName: pulumi.String("my_listing"),
			Description:  pulumi.String("example data exchange"),
			Location:     pulumi.String("US"),
		})
		if err != nil {
			return err
		}
		_, err = bigqueryanalyticshub.NewListing(ctx, "listing", &bigqueryanalyticshub.ListingArgs{
			Location:       pulumi.String("US"),
			DataExchangeId: listing.DataExchangeId,
			ListingId:      pulumi.String("my_listing"),
			DisplayName:    pulumi.String("my_listing"),
			Description:    pulumi.String("example data exchange"),
			BigqueryDataset: &bigqueryanalyticshub.ListingBigqueryDatasetArgs{
				Dataset: listingDataset.ID(),
			},
			RestrictedExportConfig: &bigqueryanalyticshub.ListingRestrictedExportConfigArgs{
				Enabled:             pulumi.Bool(true),
				RestrictQueryResult: pulumi.Bool(true),
			},
		})
		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 listing = new Gcp.BigQueryAnalyticsHub.DataExchange("listing", new()
    {
        Location = "US",
        DataExchangeId = "my_data_exchange",
        DisplayName = "my_data_exchange",
        Description = "example data exchange",
    });

    var listingDataset = new Gcp.BigQuery.Dataset("listing", new()
    {
        DatasetId = "my_listing",
        FriendlyName = "my_listing",
        Description = "example data exchange",
        Location = "US",
    });

    var listingListing = new Gcp.BigQueryAnalyticsHub.Listing("listing", new()
    {
        Location = "US",
        DataExchangeId = listing.DataExchangeId,
        ListingId = "my_listing",
        DisplayName = "my_listing",
        Description = "example data exchange",
        BigqueryDataset = new Gcp.BigQueryAnalyticsHub.Inputs.ListingBigqueryDatasetArgs
        {
            Dataset = listingDataset.Id,
        },
        RestrictedExportConfig = new Gcp.BigQueryAnalyticsHub.Inputs.ListingRestrictedExportConfigArgs
        {
            Enabled = true,
            RestrictQueryResult = true,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigqueryanalyticshub.DataExchange;
import com.pulumi.gcp.bigqueryanalyticshub.DataExchangeArgs;
import com.pulumi.gcp.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.bigqueryanalyticshub.Listing;
import com.pulumi.gcp.bigqueryanalyticshub.ListingArgs;
import com.pulumi.gcp.bigqueryanalyticshub.inputs.ListingBigqueryDatasetArgs;
import com.pulumi.gcp.bigqueryanalyticshub.inputs.ListingRestrictedExportConfigArgs;
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 listing = new DataExchange("listing", DataExchangeArgs.builder()
            .location("US")
            .dataExchangeId("my_data_exchange")
            .displayName("my_data_exchange")
            .description("example data exchange")
            .build());

        var listingDataset = new Dataset("listingDataset", DatasetArgs.builder()
            .datasetId("my_listing")
            .friendlyName("my_listing")
            .description("example data exchange")
            .location("US")
            .build());

        var listingListing = new Listing("listingListing", ListingArgs.builder()
            .location("US")
            .dataExchangeId(listing.dataExchangeId())
            .listingId("my_listing")
            .displayName("my_listing")
            .description("example data exchange")
            .bigqueryDataset(ListingBigqueryDatasetArgs.builder()
                .dataset(listingDataset.id())
                .build())
            .restrictedExportConfig(ListingRestrictedExportConfigArgs.builder()
                .enabled(true)
                .restrictQueryResult(true)
                .build())
            .build());

    }
}
resources:
  listing:
    type: gcp:bigqueryanalyticshub:DataExchange
    properties:
      location: US
      dataExchangeId: my_data_exchange
      displayName: my_data_exchange
      description: example data exchange
  listingListing:
    type: gcp:bigqueryanalyticshub:Listing
    name: listing
    properties:
      location: US
      dataExchangeId: ${listing.dataExchangeId}
      listingId: my_listing
      displayName: my_listing
      description: example data exchange
      bigqueryDataset:
        dataset: ${listingDataset.id}
      restrictedExportConfig:
        enabled: true
        restrictQueryResult: true
  listingDataset:
    type: gcp:bigquery:Dataset
    name: listing
    properties:
      datasetId: my_listing
      friendlyName: my_listing
      description: example data exchange
      location: US

The restrictedExportConfig block controls data movement. Setting enabled to true activates export restrictions, and restrictQueryResult prevents subscribers from persisting query results. These restrictions apply to all queries against the linked dataset, ensuring data stays within the controlled environment.

Share specific tables in a DCR exchange

Data Clean Room (DCR) exchanges enable privacy-preserving data collaboration by restricting what subscribers can access. Rather than sharing entire datasets, you can select specific tables to include in the listing.

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

const listing = new gcp.bigqueryanalyticshub.DataExchange("listing", {
    location: "US",
    dataExchangeId: "dcr_data_exchange",
    displayName: "dcr_data_exchange",
    description: "example dcr data exchange",
    sharingEnvironmentConfig: {
        dcrExchangeConfig: {},
    },
});
const listingDataset = new gcp.bigquery.Dataset("listing", {
    datasetId: "dcr_listing",
    friendlyName: "dcr_listing",
    description: "example dcr data exchange",
    location: "US",
});
const listingTable = new gcp.bigquery.Table("listing", {
    deletionProtection: false,
    tableId: "dcr_listing",
    datasetId: listingDataset.datasetId,
    schema: `[
  {
    \\"name\\": \\"name\\",
    \\"type\\": \\"STRING\\",
    \\"mode\\": \\"NULLABLE\\"
  },
  {
    \\"name\\": \\"post_abbr\\",
    \\"type\\": \\"STRING\\",
    \\"mode\\": \\"NULLABLE\\"
  },
  {
    \\"name\\": \\"date\\",
    \\"type\\": \\"DATE\\",
    \\"mode\\": \\"NULLABLE\\"
  }
]
`,
});
const listingListing = new gcp.bigqueryanalyticshub.Listing("listing", {
    location: "US",
    dataExchangeId: listing.dataExchangeId,
    listingId: "dcr_listing",
    displayName: "dcr_listing",
    description: "example dcr data exchange",
    bigqueryDataset: {
        dataset: listingDataset.id,
        selectedResources: [{
            table: listingTable.id,
        }],
    },
    restrictedExportConfig: {
        enabled: true,
    },
});
import pulumi
import pulumi_gcp as gcp

listing = gcp.bigqueryanalyticshub.DataExchange("listing",
    location="US",
    data_exchange_id="dcr_data_exchange",
    display_name="dcr_data_exchange",
    description="example dcr data exchange",
    sharing_environment_config={
        "dcr_exchange_config": {},
    })
listing_dataset = gcp.bigquery.Dataset("listing",
    dataset_id="dcr_listing",
    friendly_name="dcr_listing",
    description="example dcr data exchange",
    location="US")
listing_table = gcp.bigquery.Table("listing",
    deletion_protection=False,
    table_id="dcr_listing",
    dataset_id=listing_dataset.dataset_id,
    schema="""[
  {
    \"name\": \"name\",
    \"type\": \"STRING\",
    \"mode\": \"NULLABLE\"
  },
  {
    \"name\": \"post_abbr\",
    \"type\": \"STRING\",
    \"mode\": \"NULLABLE\"
  },
  {
    \"name\": \"date\",
    \"type\": \"DATE\",
    \"mode\": \"NULLABLE\"
  }
]
""")
listing_listing = gcp.bigqueryanalyticshub.Listing("listing",
    location="US",
    data_exchange_id=listing.data_exchange_id,
    listing_id="dcr_listing",
    display_name="dcr_listing",
    description="example dcr data exchange",
    bigquery_dataset={
        "dataset": listing_dataset.id,
        "selected_resources": [{
            "table": listing_table.id,
        }],
    },
    restricted_export_config={
        "enabled": True,
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		listing, err := bigqueryanalyticshub.NewDataExchange(ctx, "listing", &bigqueryanalyticshub.DataExchangeArgs{
			Location:       pulumi.String("US"),
			DataExchangeId: pulumi.String("dcr_data_exchange"),
			DisplayName:    pulumi.String("dcr_data_exchange"),
			Description:    pulumi.String("example dcr data exchange"),
			SharingEnvironmentConfig: &bigqueryanalyticshub.DataExchangeSharingEnvironmentConfigArgs{
				DcrExchangeConfig: &bigqueryanalyticshub.DataExchangeSharingEnvironmentConfigDcrExchangeConfigArgs{},
			},
		})
		if err != nil {
			return err
		}
		listingDataset, err := bigquery.NewDataset(ctx, "listing", &bigquery.DatasetArgs{
			DatasetId:    pulumi.String("dcr_listing"),
			FriendlyName: pulumi.String("dcr_listing"),
			Description:  pulumi.String("example dcr data exchange"),
			Location:     pulumi.String("US"),
		})
		if err != nil {
			return err
		}
		listingTable, err := bigquery.NewTable(ctx, "listing", &bigquery.TableArgs{
			DeletionProtection: pulumi.Bool(false),
			TableId:            pulumi.String("dcr_listing"),
			DatasetId:          listingDataset.DatasetId,
			Schema: pulumi.String(`[
  {
    \"name\": \"name\",
    \"type\": \"STRING\",
    \"mode\": \"NULLABLE\"
  },
  {
    \"name\": \"post_abbr\",
    \"type\": \"STRING\",
    \"mode\": \"NULLABLE\"
  },
  {
    \"name\": \"date\",
    \"type\": \"DATE\",
    \"mode\": \"NULLABLE\"
  }
]
`),
		})
		if err != nil {
			return err
		}
		_, err = bigqueryanalyticshub.NewListing(ctx, "listing", &bigqueryanalyticshub.ListingArgs{
			Location:       pulumi.String("US"),
			DataExchangeId: listing.DataExchangeId,
			ListingId:      pulumi.String("dcr_listing"),
			DisplayName:    pulumi.String("dcr_listing"),
			Description:    pulumi.String("example dcr data exchange"),
			BigqueryDataset: &bigqueryanalyticshub.ListingBigqueryDatasetArgs{
				Dataset: listingDataset.ID(),
				SelectedResources: bigqueryanalyticshub.ListingBigqueryDatasetSelectedResourceArray{
					&bigqueryanalyticshub.ListingBigqueryDatasetSelectedResourceArgs{
						Table: listingTable.ID(),
					},
				},
			},
			RestrictedExportConfig: &bigqueryanalyticshub.ListingRestrictedExportConfigArgs{
				Enabled: pulumi.Bool(true),
			},
		})
		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 listing = new Gcp.BigQueryAnalyticsHub.DataExchange("listing", new()
    {
        Location = "US",
        DataExchangeId = "dcr_data_exchange",
        DisplayName = "dcr_data_exchange",
        Description = "example dcr data exchange",
        SharingEnvironmentConfig = new Gcp.BigQueryAnalyticsHub.Inputs.DataExchangeSharingEnvironmentConfigArgs
        {
            DcrExchangeConfig = null,
        },
    });

    var listingDataset = new Gcp.BigQuery.Dataset("listing", new()
    {
        DatasetId = "dcr_listing",
        FriendlyName = "dcr_listing",
        Description = "example dcr data exchange",
        Location = "US",
    });

    var listingTable = new Gcp.BigQuery.Table("listing", new()
    {
        DeletionProtection = false,
        TableId = "dcr_listing",
        DatasetId = listingDataset.DatasetId,
        Schema = @"[
  {
    \""name\"": \""name\"",
    \""type\"": \""STRING\"",
    \""mode\"": \""NULLABLE\""
  },
  {
    \""name\"": \""post_abbr\"",
    \""type\"": \""STRING\"",
    \""mode\"": \""NULLABLE\""
  },
  {
    \""name\"": \""date\"",
    \""type\"": \""DATE\"",
    \""mode\"": \""NULLABLE\""
  }
]
",
    });

    var listingListing = new Gcp.BigQueryAnalyticsHub.Listing("listing", new()
    {
        Location = "US",
        DataExchangeId = listing.DataExchangeId,
        ListingId = "dcr_listing",
        DisplayName = "dcr_listing",
        Description = "example dcr data exchange",
        BigqueryDataset = new Gcp.BigQueryAnalyticsHub.Inputs.ListingBigqueryDatasetArgs
        {
            Dataset = listingDataset.Id,
            SelectedResources = new[]
            {
                new Gcp.BigQueryAnalyticsHub.Inputs.ListingBigqueryDatasetSelectedResourceArgs
                {
                    Table = listingTable.Id,
                },
            },
        },
        RestrictedExportConfig = new Gcp.BigQueryAnalyticsHub.Inputs.ListingRestrictedExportConfigArgs
        {
            Enabled = true,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigqueryanalyticshub.DataExchange;
import com.pulumi.gcp.bigqueryanalyticshub.DataExchangeArgs;
import com.pulumi.gcp.bigqueryanalyticshub.inputs.DataExchangeSharingEnvironmentConfigArgs;
import com.pulumi.gcp.bigqueryanalyticshub.inputs.DataExchangeSharingEnvironmentConfigDcrExchangeConfigArgs;
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.bigqueryanalyticshub.Listing;
import com.pulumi.gcp.bigqueryanalyticshub.ListingArgs;
import com.pulumi.gcp.bigqueryanalyticshub.inputs.ListingBigqueryDatasetArgs;
import com.pulumi.gcp.bigqueryanalyticshub.inputs.ListingRestrictedExportConfigArgs;
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 listing = new DataExchange("listing", DataExchangeArgs.builder()
            .location("US")
            .dataExchangeId("dcr_data_exchange")
            .displayName("dcr_data_exchange")
            .description("example dcr data exchange")
            .sharingEnvironmentConfig(DataExchangeSharingEnvironmentConfigArgs.builder()
                .dcrExchangeConfig(DataExchangeSharingEnvironmentConfigDcrExchangeConfigArgs.builder()
                    .build())
                .build())
            .build());

        var listingDataset = new Dataset("listingDataset", DatasetArgs.builder()
            .datasetId("dcr_listing")
            .friendlyName("dcr_listing")
            .description("example dcr data exchange")
            .location("US")
            .build());

        var listingTable = new Table("listingTable", TableArgs.builder()
            .deletionProtection(false)
            .tableId("dcr_listing")
            .datasetId(listingDataset.datasetId())
            .schema("""
[
  {
    \"name\": \"name\",
    \"type\": \"STRING\",
    \"mode\": \"NULLABLE\"
  },
  {
    \"name\": \"post_abbr\",
    \"type\": \"STRING\",
    \"mode\": \"NULLABLE\"
  },
  {
    \"name\": \"date\",
    \"type\": \"DATE\",
    \"mode\": \"NULLABLE\"
  }
]
            """)
            .build());

        var listingListing = new Listing("listingListing", ListingArgs.builder()
            .location("US")
            .dataExchangeId(listing.dataExchangeId())
            .listingId("dcr_listing")
            .displayName("dcr_listing")
            .description("example dcr data exchange")
            .bigqueryDataset(ListingBigqueryDatasetArgs.builder()
                .dataset(listingDataset.id())
                .selectedResources(ListingBigqueryDatasetSelectedResourceArgs.builder()
                    .table(listingTable.id())
                    .build())
                .build())
            .restrictedExportConfig(ListingRestrictedExportConfigArgs.builder()
                .enabled(true)
                .build())
            .build());

    }
}
resources:
  listing:
    type: gcp:bigqueryanalyticshub:DataExchange
    properties:
      location: US
      dataExchangeId: dcr_data_exchange
      displayName: dcr_data_exchange
      description: example dcr data exchange
      sharingEnvironmentConfig:
        dcrExchangeConfig: {}
  listingListing:
    type: gcp:bigqueryanalyticshub:Listing
    name: listing
    properties:
      location: US
      dataExchangeId: ${listing.dataExchangeId}
      listingId: dcr_listing
      displayName: dcr_listing
      description: example dcr data exchange
      bigqueryDataset:
        dataset: ${listingDataset.id}
        selectedResources:
          - table: ${listingTable.id}
      restrictedExportConfig:
        enabled: true
  listingDataset:
    type: gcp:bigquery:Dataset
    name: listing
    properties:
      datasetId: dcr_listing
      friendlyName: dcr_listing
      description: example dcr data exchange
      location: US
  listingTable:
    type: gcp:bigquery:Table
    name: listing
    properties:
      deletionProtection: false
      tableId: dcr_listing
      datasetId: ${listingDataset.datasetId}
      schema: |
        [
          {
            \"name\": \"name\",
            \"type\": \"STRING\",
            \"mode\": \"NULLABLE\"
          },
          {
            \"name\": \"post_abbr\",
            \"type\": \"STRING\",
            \"mode\": \"NULLABLE\"
          },
          {
            \"name\": \"date\",
            \"type\": \"DATE\",
            \"mode\": \"NULLABLE\"
          }
        ]        

The sharingEnvironmentConfig with dcrExchangeConfig marks the exchange as a Data Clean Room. The selectedResources array within bigqueryDataset specifies which tables subscribers can access. This table-level control lets you share only the data needed for collaboration while keeping other tables private.

Share Pub/Sub topics for streaming data

Analytics Hub supports sharing streaming data sources, not just static datasets. Pub/Sub topic listings enable subscribers to consume real-time event streams.

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

const listing = new gcp.bigqueryanalyticshub.DataExchange("listing", {
    location: "US",
    dataExchangeId: "tf_test_pubsub_data_exchange",
    displayName: "tf_test_pubsub_data_exchange",
    description: "Example for pubsub topic source",
});
const tfTestPubsubTopic = new gcp.pubsub.Topic("tf_test_pubsub_topic", {name: "test_pubsub"});
const listingListing = new gcp.bigqueryanalyticshub.Listing("listing", {
    location: "US",
    dataExchangeId: listing.dataExchangeId,
    listingId: "tf_test_pubsub_listing",
    displayName: "tf_test_pubsub_listing",
    description: "Example for pubsub topic source",
    pubsubTopic: {
        topic: tfTestPubsubTopic.id,
        dataAffinityRegions: [
            "us-central1",
            "europe-west1",
        ],
    },
});
import pulumi
import pulumi_gcp as gcp

listing = gcp.bigqueryanalyticshub.DataExchange("listing",
    location="US",
    data_exchange_id="tf_test_pubsub_data_exchange",
    display_name="tf_test_pubsub_data_exchange",
    description="Example for pubsub topic source")
tf_test_pubsub_topic = gcp.pubsub.Topic("tf_test_pubsub_topic", name="test_pubsub")
listing_listing = gcp.bigqueryanalyticshub.Listing("listing",
    location="US",
    data_exchange_id=listing.data_exchange_id,
    listing_id="tf_test_pubsub_listing",
    display_name="tf_test_pubsub_listing",
    description="Example for pubsub topic source",
    pubsub_topic={
        "topic": tf_test_pubsub_topic.id,
        "data_affinity_regions": [
            "us-central1",
            "europe-west1",
        ],
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		listing, err := bigqueryanalyticshub.NewDataExchange(ctx, "listing", &bigqueryanalyticshub.DataExchangeArgs{
			Location:       pulumi.String("US"),
			DataExchangeId: pulumi.String("tf_test_pubsub_data_exchange"),
			DisplayName:    pulumi.String("tf_test_pubsub_data_exchange"),
			Description:    pulumi.String("Example for pubsub topic source"),
		})
		if err != nil {
			return err
		}
		tfTestPubsubTopic, err := pubsub.NewTopic(ctx, "tf_test_pubsub_topic", &pubsub.TopicArgs{
			Name: pulumi.String("test_pubsub"),
		})
		if err != nil {
			return err
		}
		_, err = bigqueryanalyticshub.NewListing(ctx, "listing", &bigqueryanalyticshub.ListingArgs{
			Location:       pulumi.String("US"),
			DataExchangeId: listing.DataExchangeId,
			ListingId:      pulumi.String("tf_test_pubsub_listing"),
			DisplayName:    pulumi.String("tf_test_pubsub_listing"),
			Description:    pulumi.String("Example for pubsub topic source"),
			PubsubTopic: &bigqueryanalyticshub.ListingPubsubTopicArgs{
				Topic: tfTestPubsubTopic.ID(),
				DataAffinityRegions: pulumi.StringArray{
					pulumi.String("us-central1"),
					pulumi.String("europe-west1"),
				},
			},
		})
		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 listing = new Gcp.BigQueryAnalyticsHub.DataExchange("listing", new()
    {
        Location = "US",
        DataExchangeId = "tf_test_pubsub_data_exchange",
        DisplayName = "tf_test_pubsub_data_exchange",
        Description = "Example for pubsub topic source",
    });

    var tfTestPubsubTopic = new Gcp.PubSub.Topic("tf_test_pubsub_topic", new()
    {
        Name = "test_pubsub",
    });

    var listingListing = new Gcp.BigQueryAnalyticsHub.Listing("listing", new()
    {
        Location = "US",
        DataExchangeId = listing.DataExchangeId,
        ListingId = "tf_test_pubsub_listing",
        DisplayName = "tf_test_pubsub_listing",
        Description = "Example for pubsub topic source",
        PubsubTopic = new Gcp.BigQueryAnalyticsHub.Inputs.ListingPubsubTopicArgs
        {
            Topic = tfTestPubsubTopic.Id,
            DataAffinityRegions = new[]
            {
                "us-central1",
                "europe-west1",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigqueryanalyticshub.DataExchange;
import com.pulumi.gcp.bigqueryanalyticshub.DataExchangeArgs;
import com.pulumi.gcp.pubsub.Topic;
import com.pulumi.gcp.pubsub.TopicArgs;
import com.pulumi.gcp.bigqueryanalyticshub.Listing;
import com.pulumi.gcp.bigqueryanalyticshub.ListingArgs;
import com.pulumi.gcp.bigqueryanalyticshub.inputs.ListingPubsubTopicArgs;
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 listing = new DataExchange("listing", DataExchangeArgs.builder()
            .location("US")
            .dataExchangeId("tf_test_pubsub_data_exchange")
            .displayName("tf_test_pubsub_data_exchange")
            .description("Example for pubsub topic source")
            .build());

        var tfTestPubsubTopic = new Topic("tfTestPubsubTopic", TopicArgs.builder()
            .name("test_pubsub")
            .build());

        var listingListing = new Listing("listingListing", ListingArgs.builder()
            .location("US")
            .dataExchangeId(listing.dataExchangeId())
            .listingId("tf_test_pubsub_listing")
            .displayName("tf_test_pubsub_listing")
            .description("Example for pubsub topic source")
            .pubsubTopic(ListingPubsubTopicArgs.builder()
                .topic(tfTestPubsubTopic.id())
                .dataAffinityRegions(                
                    "us-central1",
                    "europe-west1")
                .build())
            .build());

    }
}
resources:
  listing:
    type: gcp:bigqueryanalyticshub:DataExchange
    properties:
      location: US
      dataExchangeId: tf_test_pubsub_data_exchange
      displayName: tf_test_pubsub_data_exchange
      description: Example for pubsub topic source
  tfTestPubsubTopic:
    type: gcp:pubsub:Topic
    name: tf_test_pubsub_topic
    properties:
      name: test_pubsub
  listingListing:
    type: gcp:bigqueryanalyticshub:Listing
    name: listing
    properties:
      location: US
      dataExchangeId: ${listing.dataExchangeId}
      listingId: tf_test_pubsub_listing
      displayName: tf_test_pubsub_listing
      description: Example for pubsub topic source
      pubsubTopic:
        topic: ${tfTestPubsubTopic.id}
        dataAffinityRegions:
          - us-central1
          - europe-west1

The pubsubTopic property replaces bigqueryDataset for streaming sources. The topic property references the Pub/Sub topic by ID, and dataAffinityRegions specifies where subscriber data should be processed. Subscribers receive a linked subscription that delivers messages from the shared topic.

Enable subscriber query logging

Data providers sometimes need to track who queries their shared datasets for compliance or usage analysis.

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

const listingLogEmail = new gcp.bigqueryanalyticshub.DataExchange("listing_log_email", {
    location: "US",
    dataExchangeId: "tf_test_log_email_de",
    displayName: "tf_test_log_email_de",
    description: "Example for log email test",
});
const listingLogEmailDataset = new gcp.bigquery.Dataset("listing_log_email", {
    datasetId: "tf_test_log_email_ds",
    friendlyName: "tf_test_log_email_ds",
    description: "Example for log email test",
    location: "US",
});
const listing = new gcp.bigqueryanalyticshub.Listing("listing", {
    location: "US",
    dataExchangeId: listingLogEmail.dataExchangeId,
    listingId: "tf_test_log_email_listing",
    displayName: "tf_test_log_email_listing",
    description: "Example for log email test",
    logLinkedDatasetQueryUserEmail: true,
    bigqueryDataset: {
        dataset: listingLogEmailDataset.id,
    },
});
import pulumi
import pulumi_gcp as gcp

listing_log_email = gcp.bigqueryanalyticshub.DataExchange("listing_log_email",
    location="US",
    data_exchange_id="tf_test_log_email_de",
    display_name="tf_test_log_email_de",
    description="Example for log email test")
listing_log_email_dataset = gcp.bigquery.Dataset("listing_log_email",
    dataset_id="tf_test_log_email_ds",
    friendly_name="tf_test_log_email_ds",
    description="Example for log email test",
    location="US")
listing = gcp.bigqueryanalyticshub.Listing("listing",
    location="US",
    data_exchange_id=listing_log_email.data_exchange_id,
    listing_id="tf_test_log_email_listing",
    display_name="tf_test_log_email_listing",
    description="Example for log email test",
    log_linked_dataset_query_user_email=True,
    bigquery_dataset={
        "dataset": listing_log_email_dataset.id,
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		listingLogEmail, err := bigqueryanalyticshub.NewDataExchange(ctx, "listing_log_email", &bigqueryanalyticshub.DataExchangeArgs{
			Location:       pulumi.String("US"),
			DataExchangeId: pulumi.String("tf_test_log_email_de"),
			DisplayName:    pulumi.String("tf_test_log_email_de"),
			Description:    pulumi.String("Example for log email test"),
		})
		if err != nil {
			return err
		}
		listingLogEmailDataset, err := bigquery.NewDataset(ctx, "listing_log_email", &bigquery.DatasetArgs{
			DatasetId:    pulumi.String("tf_test_log_email_ds"),
			FriendlyName: pulumi.String("tf_test_log_email_ds"),
			Description:  pulumi.String("Example for log email test"),
			Location:     pulumi.String("US"),
		})
		if err != nil {
			return err
		}
		_, err = bigqueryanalyticshub.NewListing(ctx, "listing", &bigqueryanalyticshub.ListingArgs{
			Location:                       pulumi.String("US"),
			DataExchangeId:                 listingLogEmail.DataExchangeId,
			ListingId:                      pulumi.String("tf_test_log_email_listing"),
			DisplayName:                    pulumi.String("tf_test_log_email_listing"),
			Description:                    pulumi.String("Example for log email test"),
			LogLinkedDatasetQueryUserEmail: pulumi.Bool(true),
			BigqueryDataset: &bigqueryanalyticshub.ListingBigqueryDatasetArgs{
				Dataset: listingLogEmailDataset.ID(),
			},
		})
		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 listingLogEmail = new Gcp.BigQueryAnalyticsHub.DataExchange("listing_log_email", new()
    {
        Location = "US",
        DataExchangeId = "tf_test_log_email_de",
        DisplayName = "tf_test_log_email_de",
        Description = "Example for log email test",
    });

    var listingLogEmailDataset = new Gcp.BigQuery.Dataset("listing_log_email", new()
    {
        DatasetId = "tf_test_log_email_ds",
        FriendlyName = "tf_test_log_email_ds",
        Description = "Example for log email test",
        Location = "US",
    });

    var listing = new Gcp.BigQueryAnalyticsHub.Listing("listing", new()
    {
        Location = "US",
        DataExchangeId = listingLogEmail.DataExchangeId,
        ListingId = "tf_test_log_email_listing",
        DisplayName = "tf_test_log_email_listing",
        Description = "Example for log email test",
        LogLinkedDatasetQueryUserEmail = true,
        BigqueryDataset = new Gcp.BigQueryAnalyticsHub.Inputs.ListingBigqueryDatasetArgs
        {
            Dataset = listingLogEmailDataset.Id,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigqueryanalyticshub.DataExchange;
import com.pulumi.gcp.bigqueryanalyticshub.DataExchangeArgs;
import com.pulumi.gcp.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.bigqueryanalyticshub.Listing;
import com.pulumi.gcp.bigqueryanalyticshub.ListingArgs;
import com.pulumi.gcp.bigqueryanalyticshub.inputs.ListingBigqueryDatasetArgs;
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 listingLogEmail = new DataExchange("listingLogEmail", DataExchangeArgs.builder()
            .location("US")
            .dataExchangeId("tf_test_log_email_de")
            .displayName("tf_test_log_email_de")
            .description("Example for log email test")
            .build());

        var listingLogEmailDataset = new Dataset("listingLogEmailDataset", DatasetArgs.builder()
            .datasetId("tf_test_log_email_ds")
            .friendlyName("tf_test_log_email_ds")
            .description("Example for log email test")
            .location("US")
            .build());

        var listing = new Listing("listing", ListingArgs.builder()
            .location("US")
            .dataExchangeId(listingLogEmail.dataExchangeId())
            .listingId("tf_test_log_email_listing")
            .displayName("tf_test_log_email_listing")
            .description("Example for log email test")
            .logLinkedDatasetQueryUserEmail(true)
            .bigqueryDataset(ListingBigqueryDatasetArgs.builder()
                .dataset(listingLogEmailDataset.id())
                .build())
            .build());

    }
}
resources:
  listingLogEmail:
    type: gcp:bigqueryanalyticshub:DataExchange
    name: listing_log_email
    properties:
      location: US
      dataExchangeId: tf_test_log_email_de
      displayName: tf_test_log_email_de
      description: Example for log email test
  listing:
    type: gcp:bigqueryanalyticshub:Listing
    properties:
      location: US
      dataExchangeId: ${listingLogEmail.dataExchangeId}
      listingId: tf_test_log_email_listing
      displayName: tf_test_log_email_listing
      description: Example for log email test
      logLinkedDatasetQueryUserEmail: true
      bigqueryDataset:
        dataset: ${listingLogEmailDataset.id}
  listingLogEmailDataset:
    type: gcp:bigquery:Dataset
    name: listing_log_email
    properties:
      datasetId: tf_test_log_email_ds
      friendlyName: tf_test_log_email_ds
      description: Example for log email test
      location: US

Setting logLinkedDatasetQueryUserEmail to true captures subscriber email addresses for all queries against the linked dataset. This creates an audit trail of who accessed the data. Note that once enabled, this setting cannot be disabled.

Make listings publicly discoverable

Public listings appear on the Analytics Hub discovery page, making them visible to all users who can access the exchange.

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

const listing = new gcp.bigqueryanalyticshub.DataExchange("listing", {
    location: "US",
    dataExchangeId: "my_data_exchange",
    displayName: "my_data_exchange",
    description: "example public listing",
    discoveryType: "DISCOVERY_TYPE_PUBLIC",
});
const listingDataset = new gcp.bigquery.Dataset("listing", {
    datasetId: "my_listing",
    friendlyName: "my_listing",
    description: "example public listing",
    location: "US",
});
const listingListing = new gcp.bigqueryanalyticshub.Listing("listing", {
    location: "US",
    dataExchangeId: listing.dataExchangeId,
    listingId: "my_listing",
    displayName: "my_listing",
    description: "example public listing",
    discoveryType: "DISCOVERY_TYPE_PUBLIC",
    allowOnlyMetadataSharing: false,
    bigqueryDataset: {
        dataset: listingDataset.id,
    },
});
import pulumi
import pulumi_gcp as gcp

listing = gcp.bigqueryanalyticshub.DataExchange("listing",
    location="US",
    data_exchange_id="my_data_exchange",
    display_name="my_data_exchange",
    description="example public listing",
    discovery_type="DISCOVERY_TYPE_PUBLIC")
listing_dataset = gcp.bigquery.Dataset("listing",
    dataset_id="my_listing",
    friendly_name="my_listing",
    description="example public listing",
    location="US")
listing_listing = gcp.bigqueryanalyticshub.Listing("listing",
    location="US",
    data_exchange_id=listing.data_exchange_id,
    listing_id="my_listing",
    display_name="my_listing",
    description="example public listing",
    discovery_type="DISCOVERY_TYPE_PUBLIC",
    allow_only_metadata_sharing=False,
    bigquery_dataset={
        "dataset": listing_dataset.id,
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		listing, err := bigqueryanalyticshub.NewDataExchange(ctx, "listing", &bigqueryanalyticshub.DataExchangeArgs{
			Location:       pulumi.String("US"),
			DataExchangeId: pulumi.String("my_data_exchange"),
			DisplayName:    pulumi.String("my_data_exchange"),
			Description:    pulumi.String("example public listing"),
			DiscoveryType:  pulumi.String("DISCOVERY_TYPE_PUBLIC"),
		})
		if err != nil {
			return err
		}
		listingDataset, err := bigquery.NewDataset(ctx, "listing", &bigquery.DatasetArgs{
			DatasetId:    pulumi.String("my_listing"),
			FriendlyName: pulumi.String("my_listing"),
			Description:  pulumi.String("example public listing"),
			Location:     pulumi.String("US"),
		})
		if err != nil {
			return err
		}
		_, err = bigqueryanalyticshub.NewListing(ctx, "listing", &bigqueryanalyticshub.ListingArgs{
			Location:                 pulumi.String("US"),
			DataExchangeId:           listing.DataExchangeId,
			ListingId:                pulumi.String("my_listing"),
			DisplayName:              pulumi.String("my_listing"),
			Description:              pulumi.String("example public listing"),
			DiscoveryType:            pulumi.String("DISCOVERY_TYPE_PUBLIC"),
			AllowOnlyMetadataSharing: pulumi.Bool(false),
			BigqueryDataset: &bigqueryanalyticshub.ListingBigqueryDatasetArgs{
				Dataset: listingDataset.ID(),
			},
		})
		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 listing = new Gcp.BigQueryAnalyticsHub.DataExchange("listing", new()
    {
        Location = "US",
        DataExchangeId = "my_data_exchange",
        DisplayName = "my_data_exchange",
        Description = "example public listing",
        DiscoveryType = "DISCOVERY_TYPE_PUBLIC",
    });

    var listingDataset = new Gcp.BigQuery.Dataset("listing", new()
    {
        DatasetId = "my_listing",
        FriendlyName = "my_listing",
        Description = "example public listing",
        Location = "US",
    });

    var listingListing = new Gcp.BigQueryAnalyticsHub.Listing("listing", new()
    {
        Location = "US",
        DataExchangeId = listing.DataExchangeId,
        ListingId = "my_listing",
        DisplayName = "my_listing",
        Description = "example public listing",
        DiscoveryType = "DISCOVERY_TYPE_PUBLIC",
        AllowOnlyMetadataSharing = false,
        BigqueryDataset = new Gcp.BigQueryAnalyticsHub.Inputs.ListingBigqueryDatasetArgs
        {
            Dataset = listingDataset.Id,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigqueryanalyticshub.DataExchange;
import com.pulumi.gcp.bigqueryanalyticshub.DataExchangeArgs;
import com.pulumi.gcp.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.bigqueryanalyticshub.Listing;
import com.pulumi.gcp.bigqueryanalyticshub.ListingArgs;
import com.pulumi.gcp.bigqueryanalyticshub.inputs.ListingBigqueryDatasetArgs;
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 listing = new DataExchange("listing", DataExchangeArgs.builder()
            .location("US")
            .dataExchangeId("my_data_exchange")
            .displayName("my_data_exchange")
            .description("example public listing")
            .discoveryType("DISCOVERY_TYPE_PUBLIC")
            .build());

        var listingDataset = new Dataset("listingDataset", DatasetArgs.builder()
            .datasetId("my_listing")
            .friendlyName("my_listing")
            .description("example public listing")
            .location("US")
            .build());

        var listingListing = new Listing("listingListing", ListingArgs.builder()
            .location("US")
            .dataExchangeId(listing.dataExchangeId())
            .listingId("my_listing")
            .displayName("my_listing")
            .description("example public listing")
            .discoveryType("DISCOVERY_TYPE_PUBLIC")
            .allowOnlyMetadataSharing(false)
            .bigqueryDataset(ListingBigqueryDatasetArgs.builder()
                .dataset(listingDataset.id())
                .build())
            .build());

    }
}
resources:
  listing:
    type: gcp:bigqueryanalyticshub:DataExchange
    properties:
      location: US
      dataExchangeId: my_data_exchange
      displayName: my_data_exchange
      description: example public listing
      discoveryType: DISCOVERY_TYPE_PUBLIC
  listingListing:
    type: gcp:bigqueryanalyticshub:Listing
    name: listing
    properties:
      location: US
      dataExchangeId: ${listing.dataExchangeId}
      listingId: my_listing
      displayName: my_listing
      description: example public listing
      discoveryType: DISCOVERY_TYPE_PUBLIC
      allowOnlyMetadataSharing: false
      bigqueryDataset:
        dataset: ${listingDataset.id}
  listingDataset:
    type: gcp:bigquery:Dataset
    name: listing
    properties:
      datasetId: my_listing
      friendlyName: my_listing
      description: example public listing
      location: US

The discoveryType property controls listing visibility. Setting it to DISCOVERY_TYPE_PUBLIC makes the listing appear on the discovery page for all users. The allowOnlyMetadataSharing property determines whether users can subscribe to the data or only view its metadata. Note that the parent DataExchange must also be configured as public for this to work.

Beyond these examples

These snippets focus on specific listing-level features: BigQuery dataset and Pub/Sub topic sharing, export restrictions and query logging, and DCR table selection and public discovery. They’re intentionally minimal rather than full data sharing solutions.

The examples reference pre-existing infrastructure such as DataExchange resources, BigQuery datasets and tables, and Pub/Sub topics for streaming listings. They focus on configuring the listing rather than provisioning the underlying data sources.

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

  • Publisher and data provider metadata (publisher, dataProvider blocks)
  • Listing categorization and documentation (categories, documentation)
  • Contact information and access requests (primaryContact, requestAccess)
  • Commercial listing configuration (deleteCommercial flag)

These omissions are intentional: the goal is to illustrate how each listing feature is wired, not provide drop-in data sharing modules. See the BigQuery Analytics Hub Listing resource reference for all available configuration options.

Let's create GCP BigQuery Analytics Hub Listings

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Immutability
What fields can't I change after creating a listing?
The following fields are immutable: dataExchangeId, listingId, location, project, allowOnlyMetadataSharing, and bigqueryDataset. You’ll need to recreate the listing to change these values.
What characters are allowed in listing and data exchange IDs?
Both listingId and dataExchangeId must contain only Unicode letters, numbers (0-9), and underscores (_). Avoid characters that require URL-escaping, non-ASCII characters, and spaces.
Data Sources & Sharing
How do I share a BigQuery dataset through Analytics Hub?
Configure the bigqueryDataset property with a reference to your dataset ID, as shown in the basic example.
How do I share specific tables or routines instead of an entire dataset?
Use bigqueryDataset.selectedResources with table or routine IDs to share specific resources rather than the entire dataset.
Can I share a Pub/Sub topic instead of a BigQuery dataset?
Yes, configure pubsubTopic with the topic ID and dataAffinityRegions instead of using bigqueryDataset.
Access Control & Discovery
What's the difference between private and public discovery types?
DISCOVERY_TYPE_PRIVATE listings appear only to users with IAM permissions, while DISCOVERY_TYPE_PUBLIC listings are discoverable on the public discovery page. Note that discoveryType doesn’t control IAM-based visibility.
Can I set discoveryType for a restricted listing?
No, discoveryType cannot be set for listings with restrictedExportConfig enabled.
How do I enable restricted export for a listing?
Set restrictedExportConfig.enabled to true. This configuration will be propagated and enforced on the linked dataset.
Query Logging & Monitoring
Can I turn off query user email logging once it's enabled?
No, once you enable logLinkedDatasetQueryUserEmail, it cannot be turned off. All queries on the linked dataset will permanently log the querying user’s email address.
Commercial Listings & Deletion
Why do I need to set deleteCommercial to true when deleting a listing?
For commercial listings, you must set deleteCommercial to true to confirm deletion. This safety guard prevents accidental deletion of commercial listings.

Using a different cloud?

Explore analytics guides for other cloud providers: