The gcp:datacatalog/entry:Entry resource, part of the Pulumi GCP provider, registers resources in Data Catalog with metadata, schemas, and type information. Data Catalog is deprecated and will be discontinued on January 30, 2026; for migration guidance, see the Dataplex Catalog transition documentation. This guide focuses on three capabilities: custom type registration for external systems, Cloud Storage fileset cataloging, and schema documentation.
Entries belong to entry groups and may reference Cloud Storage buckets or external systems that exist outside the catalog. The examples are intentionally small. Combine them with your own entry group organization and metadata standards.
Catalog external resources with custom types
Teams cataloging resources outside Google Cloud register them with custom type identifiers that describe the external system.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const entryGroup = new gcp.datacatalog.EntryGroup("entry_group", {entryGroupId: "my_group"});
const basicEntry = new gcp.datacatalog.Entry("basic_entry", {
entryGroup: entryGroup.id,
entryId: "my_entry",
userSpecifiedType: "my_custom_type",
userSpecifiedSystem: "SomethingExternal",
});
import pulumi
import pulumi_gcp as gcp
entry_group = gcp.datacatalog.EntryGroup("entry_group", entry_group_id="my_group")
basic_entry = gcp.datacatalog.Entry("basic_entry",
entry_group=entry_group.id,
entry_id="my_entry",
user_specified_type="my_custom_type",
user_specified_system="SomethingExternal")
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/datacatalog"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
entryGroup, err := datacatalog.NewEntryGroup(ctx, "entry_group", &datacatalog.EntryGroupArgs{
EntryGroupId: pulumi.String("my_group"),
})
if err != nil {
return err
}
_, err = datacatalog.NewEntry(ctx, "basic_entry", &datacatalog.EntryArgs{
EntryGroup: entryGroup.ID(),
EntryId: pulumi.String("my_entry"),
UserSpecifiedType: pulumi.String("my_custom_type"),
UserSpecifiedSystem: pulumi.String("SomethingExternal"),
})
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 entryGroup = new Gcp.DataCatalog.EntryGroup("entry_group", new()
{
EntryGroupId = "my_group",
});
var basicEntry = new Gcp.DataCatalog.Entry("basic_entry", new()
{
EntryGroup = entryGroup.Id,
EntryId = "my_entry",
UserSpecifiedType = "my_custom_type",
UserSpecifiedSystem = "SomethingExternal",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.datacatalog.EntryGroup;
import com.pulumi.gcp.datacatalog.EntryGroupArgs;
import com.pulumi.gcp.datacatalog.Entry;
import com.pulumi.gcp.datacatalog.EntryArgs;
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 entryGroup = new EntryGroup("entryGroup", EntryGroupArgs.builder()
.entryGroupId("my_group")
.build());
var basicEntry = new Entry("basicEntry", EntryArgs.builder()
.entryGroup(entryGroup.id())
.entryId("my_entry")
.userSpecifiedType("my_custom_type")
.userSpecifiedSystem("SomethingExternal")
.build());
}
}
resources:
basicEntry:
type: gcp:datacatalog:Entry
name: basic_entry
properties:
entryGroup: ${entryGroup.id}
entryId: my_entry
userSpecifiedType: my_custom_type
userSpecifiedSystem: SomethingExternal
entryGroup:
type: gcp:datacatalog:EntryGroup
name: entry_group
properties:
entryGroupId: my_group
The userSpecifiedType and userSpecifiedSystem properties label the entry with custom identifiers when the resource doesn’t match Data Catalog’s built-in types. The entryGroup places the entry in an organizational container, and entryId provides a unique identifier within that group.
Catalog Cloud Storage filesets with patterns
Data pipelines working with file collections in Cloud Storage can track them as single logical entities using fileset entries.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const entryGroup = new gcp.datacatalog.EntryGroup("entry_group", {entryGroupId: "my_group"});
const basicEntry = new gcp.datacatalog.Entry("basic_entry", {
entryGroup: entryGroup.id,
entryId: "my_entry",
type: "FILESET",
gcsFilesetSpec: {
filePatterns: ["gs://fake_bucket/dir/*"],
},
});
import pulumi
import pulumi_gcp as gcp
entry_group = gcp.datacatalog.EntryGroup("entry_group", entry_group_id="my_group")
basic_entry = gcp.datacatalog.Entry("basic_entry",
entry_group=entry_group.id,
entry_id="my_entry",
type="FILESET",
gcs_fileset_spec={
"file_patterns": ["gs://fake_bucket/dir/*"],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/datacatalog"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
entryGroup, err := datacatalog.NewEntryGroup(ctx, "entry_group", &datacatalog.EntryGroupArgs{
EntryGroupId: pulumi.String("my_group"),
})
if err != nil {
return err
}
_, err = datacatalog.NewEntry(ctx, "basic_entry", &datacatalog.EntryArgs{
EntryGroup: entryGroup.ID(),
EntryId: pulumi.String("my_entry"),
Type: pulumi.String("FILESET"),
GcsFilesetSpec: &datacatalog.EntryGcsFilesetSpecArgs{
FilePatterns: pulumi.StringArray{
pulumi.String("gs://fake_bucket/dir/*"),
},
},
})
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 entryGroup = new Gcp.DataCatalog.EntryGroup("entry_group", new()
{
EntryGroupId = "my_group",
});
var basicEntry = new Gcp.DataCatalog.Entry("basic_entry", new()
{
EntryGroup = entryGroup.Id,
EntryId = "my_entry",
Type = "FILESET",
GcsFilesetSpec = new Gcp.DataCatalog.Inputs.EntryGcsFilesetSpecArgs
{
FilePatterns = new[]
{
"gs://fake_bucket/dir/*",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.datacatalog.EntryGroup;
import com.pulumi.gcp.datacatalog.EntryGroupArgs;
import com.pulumi.gcp.datacatalog.Entry;
import com.pulumi.gcp.datacatalog.EntryArgs;
import com.pulumi.gcp.datacatalog.inputs.EntryGcsFilesetSpecArgs;
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 entryGroup = new EntryGroup("entryGroup", EntryGroupArgs.builder()
.entryGroupId("my_group")
.build());
var basicEntry = new Entry("basicEntry", EntryArgs.builder()
.entryGroup(entryGroup.id())
.entryId("my_entry")
.type("FILESET")
.gcsFilesetSpec(EntryGcsFilesetSpecArgs.builder()
.filePatterns("gs://fake_bucket/dir/*")
.build())
.build());
}
}
resources:
basicEntry:
type: gcp:datacatalog:Entry
name: basic_entry
properties:
entryGroup: ${entryGroup.id}
entryId: my_entry
type: FILESET
gcsFilesetSpec:
filePatterns:
- gs://fake_bucket/dir/*
entryGroup:
type: gcp:datacatalog:EntryGroup
name: entry_group
properties:
entryGroupId: my_group
The type property set to FILESET tells Data Catalog this entry represents a collection of files. The gcsFilesetSpec.filePatterns property uses glob patterns to define which files belong to the set, allowing wildcards to match multiple objects.
Document entries with schema and metadata
Production catalogs need rich metadata including schemas, descriptions, and links to help users understand data contents and origins.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const entryGroup = new gcp.datacatalog.EntryGroup("entry_group", {entryGroupId: "my_group"});
const basicEntry = new gcp.datacatalog.Entry("basic_entry", {
entryGroup: entryGroup.id,
entryId: "my_entry",
userSpecifiedType: "my_user_specified_type",
userSpecifiedSystem: "Something_custom",
linkedResource: "my/linked/resource",
displayName: "my custom type entry",
description: "a custom type entry for a user specified system",
schema: `{
\\"columns\\": [
{
\\"column\\": \\"first_name\\",
\\"description\\": \\"First name\\",
\\"mode\\": \\"REQUIRED\\",
\\"type\\": \\"STRING\\"
},
{
\\"column\\": \\"last_name\\",
\\"description\\": \\"Last name\\",
\\"mode\\": \\"REQUIRED\\",
\\"type\\": \\"STRING\\"
},
{
\\"column\\": \\"address\\",
\\"description\\": \\"Address\\",
\\"mode\\": \\"REPEATED\\",
\\"subcolumns\\": [
{
\\"column\\": \\"city\\",
\\"description\\": \\"City\\",
\\"mode\\": \\"NULLABLE\\",
\\"type\\": \\"STRING\\"
},
{
\\"column\\": \\"state\\",
\\"description\\": \\"State\\",
\\"mode\\": \\"NULLABLE\\",
\\"type\\": \\"STRING\\"
}
],
\\"type\\": \\"RECORD\\"
}
]
}
`,
});
import pulumi
import pulumi_gcp as gcp
entry_group = gcp.datacatalog.EntryGroup("entry_group", entry_group_id="my_group")
basic_entry = gcp.datacatalog.Entry("basic_entry",
entry_group=entry_group.id,
entry_id="my_entry",
user_specified_type="my_user_specified_type",
user_specified_system="Something_custom",
linked_resource="my/linked/resource",
display_name="my custom type entry",
description="a custom type entry for a user specified system",
schema="""{
\"columns\": [
{
\"column\": \"first_name\",
\"description\": \"First name\",
\"mode\": \"REQUIRED\",
\"type\": \"STRING\"
},
{
\"column\": \"last_name\",
\"description\": \"Last name\",
\"mode\": \"REQUIRED\",
\"type\": \"STRING\"
},
{
\"column\": \"address\",
\"description\": \"Address\",
\"mode\": \"REPEATED\",
\"subcolumns\": [
{
\"column\": \"city\",
\"description\": \"City\",
\"mode\": \"NULLABLE\",
\"type\": \"STRING\"
},
{
\"column\": \"state\",
\"description\": \"State\",
\"mode\": \"NULLABLE\",
\"type\": \"STRING\"
}
],
\"type\": \"RECORD\"
}
]
}
""")
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/datacatalog"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
entryGroup, err := datacatalog.NewEntryGroup(ctx, "entry_group", &datacatalog.EntryGroupArgs{
EntryGroupId: pulumi.String("my_group"),
})
if err != nil {
return err
}
_, err = datacatalog.NewEntry(ctx, "basic_entry", &datacatalog.EntryArgs{
EntryGroup: entryGroup.ID(),
EntryId: pulumi.String("my_entry"),
UserSpecifiedType: pulumi.String("my_user_specified_type"),
UserSpecifiedSystem: pulumi.String("Something_custom"),
LinkedResource: pulumi.String("my/linked/resource"),
DisplayName: pulumi.String("my custom type entry"),
Description: pulumi.String("a custom type entry for a user specified system"),
Schema: pulumi.String(`{
\"columns\": [
{
\"column\": \"first_name\",
\"description\": \"First name\",
\"mode\": \"REQUIRED\",
\"type\": \"STRING\"
},
{
\"column\": \"last_name\",
\"description\": \"Last name\",
\"mode\": \"REQUIRED\",
\"type\": \"STRING\"
},
{
\"column\": \"address\",
\"description\": \"Address\",
\"mode\": \"REPEATED\",
\"subcolumns\": [
{
\"column\": \"city\",
\"description\": \"City\",
\"mode\": \"NULLABLE\",
\"type\": \"STRING\"
},
{
\"column\": \"state\",
\"description\": \"State\",
\"mode\": \"NULLABLE\",
\"type\": \"STRING\"
}
],
\"type\": \"RECORD\"
}
]
}
`),
})
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 entryGroup = new Gcp.DataCatalog.EntryGroup("entry_group", new()
{
EntryGroupId = "my_group",
});
var basicEntry = new Gcp.DataCatalog.Entry("basic_entry", new()
{
EntryGroup = entryGroup.Id,
EntryId = "my_entry",
UserSpecifiedType = "my_user_specified_type",
UserSpecifiedSystem = "Something_custom",
LinkedResource = "my/linked/resource",
DisplayName = "my custom type entry",
Description = "a custom type entry for a user specified system",
Schema = @"{
\""columns\"": [
{
\""column\"": \""first_name\"",
\""description\"": \""First name\"",
\""mode\"": \""REQUIRED\"",
\""type\"": \""STRING\""
},
{
\""column\"": \""last_name\"",
\""description\"": \""Last name\"",
\""mode\"": \""REQUIRED\"",
\""type\"": \""STRING\""
},
{
\""column\"": \""address\"",
\""description\"": \""Address\"",
\""mode\"": \""REPEATED\"",
\""subcolumns\"": [
{
\""column\"": \""city\"",
\""description\"": \""City\"",
\""mode\"": \""NULLABLE\"",
\""type\"": \""STRING\""
},
{
\""column\"": \""state\"",
\""description\"": \""State\"",
\""mode\"": \""NULLABLE\"",
\""type\"": \""STRING\""
}
],
\""type\"": \""RECORD\""
}
]
}
",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.datacatalog.EntryGroup;
import com.pulumi.gcp.datacatalog.EntryGroupArgs;
import com.pulumi.gcp.datacatalog.Entry;
import com.pulumi.gcp.datacatalog.EntryArgs;
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 entryGroup = new EntryGroup("entryGroup", EntryGroupArgs.builder()
.entryGroupId("my_group")
.build());
var basicEntry = new Entry("basicEntry", EntryArgs.builder()
.entryGroup(entryGroup.id())
.entryId("my_entry")
.userSpecifiedType("my_user_specified_type")
.userSpecifiedSystem("Something_custom")
.linkedResource("my/linked/resource")
.displayName("my custom type entry")
.description("a custom type entry for a user specified system")
.schema("""
{
\"columns\": [
{
\"column\": \"first_name\",
\"description\": \"First name\",
\"mode\": \"REQUIRED\",
\"type\": \"STRING\"
},
{
\"column\": \"last_name\",
\"description\": \"Last name\",
\"mode\": \"REQUIRED\",
\"type\": \"STRING\"
},
{
\"column\": \"address\",
\"description\": \"Address\",
\"mode\": \"REPEATED\",
\"subcolumns\": [
{
\"column\": \"city\",
\"description\": \"City\",
\"mode\": \"NULLABLE\",
\"type\": \"STRING\"
},
{
\"column\": \"state\",
\"description\": \"State\",
\"mode\": \"NULLABLE\",
\"type\": \"STRING\"
}
],
\"type\": \"RECORD\"
}
]
}
""")
.build());
}
}
resources:
basicEntry:
type: gcp:datacatalog:Entry
name: basic_entry
properties:
entryGroup: ${entryGroup.id}
entryId: my_entry
userSpecifiedType: my_user_specified_type
userSpecifiedSystem: Something_custom
linkedResource: my/linked/resource
displayName: my custom type entry
description: a custom type entry for a user specified system
schema: |
{
\"columns\": [
{
\"column\": \"first_name\",
\"description\": \"First name\",
\"mode\": \"REQUIRED\",
\"type\": \"STRING\"
},
{
\"column\": \"last_name\",
\"description\": \"Last name\",
\"mode\": \"REQUIRED\",
\"type\": \"STRING\"
},
{
\"column\": \"address\",
\"description\": \"Address\",
\"mode\": \"REPEATED\",
\"subcolumns\": [
{
\"column\": \"city\",
\"description\": \"City\",
\"mode\": \"NULLABLE\",
\"type\": \"STRING\"
},
{
\"column\": \"state\",
\"description\": \"State\",
\"mode\": \"NULLABLE\",
\"type\": \"STRING\"
}
],
\"type\": \"RECORD\"
}
]
}
entryGroup:
type: gcp:datacatalog:EntryGroup
name: entry_group
properties:
entryGroupId: my_group
The schema property contains a JSON string describing the data structure with columns, types, and nested records. The displayName and description properties provide human-readable documentation. The linkedResource property connects the catalog entry back to the actual resource in its source system.
Beyond these examples
These snippets focus on specific entry-level features: custom type registration for external systems, Cloud Storage fileset cataloging, and schema documentation and metadata. They’re intentionally minimal rather than full catalog implementations.
The examples may reference pre-existing infrastructure such as Data Catalog entry groups (created inline in examples) and Cloud Storage buckets (referenced but not created). They focus on entry configuration rather than provisioning the surrounding catalog structure.
To keep things focused, common entry patterns are omitted, including:
- BigQuery table integration (integratedSystem output)
- Tag attachment for flexible metadata
- Entry group organization and permissions
- Linked resource validation and format requirements
These omissions are intentional: the goal is to illustrate how each entry feature is wired, not provide drop-in catalog modules. See the Data Catalog Entry resource reference for all available configuration options.
Let's configure GCP Data Catalog Entries
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Deprecation & Migration
gcp.datacatalog.Entry is deprecated and will be removed in a future major release. Data Catalog will be discontinued on January 30, 2026. You should transition to Dataplex Catalog using the migration guide at https://cloud.google.com/dataplex/docs/transition-to-dataplex-catalog.Entry Types & Configuration
type only for FILESET entries (the only allowed value from the EntryType enum). For all other entry types, use userSpecifiedType with a custom value since the enum is limited to FILESET.type: "FILESET" with gcsFilesetSpec for Cloud Storage filesets. For BigQuery tables, Pub/Sub topics, or external resources, use userSpecifiedType with a custom type name.userSpecifiedSystem to indicate the external source system (e.g., “SomethingExternal”) and use userSpecifiedType for the custom entry type. The linkedResource field is optional for these entries.schema field accepts a JSON string with a columns array. Each column can specify column, description, mode (REQUIRED/NULLABLE/REPEATED), type, and nested subcolumns for RECORD types.Immutability & Constraints
entryGroup, entryId, and type properties are immutable and cannot be changed after creation.userSpecifiedType and userSpecifiedSystem must begin with a letter or underscore, contain only letters, numbers, and underscores, are case insensitive, and must be 1-64 characters long.Resource References
//bigquery.googleapis.com/projects/projectId/datasets/datasetId/tables/tableId). For entries with userSpecifiedType, this field is optional and defaults to an empty string.Using a different cloud?
Explore analytics guides for other cloud providers: