The gcp:datacatalog/entry:Entry resource, part of the Pulumi GCP provider, represents resources in Google Cloud or external systems as catalog entries with metadata, schema, and searchable descriptions. 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: external resource registration with custom types, Cloud Storage fileset cataloging, and schema definition with descriptive metadata.
Entries belong to entry groups and may reference Cloud Storage buckets or external systems. The examples are intentionally small. Combine them with your own entry groups and resource references.
Register external resources with custom types
Teams cataloging resources outside Google Cloud create entries that reference external systems as metadata containers.
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 identify resources from non-integrated systems. The entryGroup property places the entry in an organizational container. This creates a catalog record without schema or detailed metadata.
Catalog Cloud Storage filesets with patterns
Data pipelines working with file collections in Cloud Storage can catalog them as single logical units 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” enables Cloud Storage-specific configuration. The gcsFilesetSpec property defines file patterns that match collections of objects. This lets you catalog directories or pattern-matched files as unified datasets.
Add schema and metadata to catalog entries
Entries become searchable and useful when they include schema definitions and descriptive metadata.
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 accepts JSON that describes columns, types, modes (REQUIRED, NULLABLE, REPEATED), and nested structures (RECORD type with subcolumns). The displayName and description properties make entries discoverable through search. The linkedResource property connects the catalog entry to the actual resource location. This extends basic registration with structure documentation.
Beyond these examples
These snippets focus on specific entry-level features: external resource registration, Cloud Storage fileset cataloging, and schema definition and metadata. They’re intentionally minimal rather than full catalog implementations.
The examples reference pre-existing infrastructure such as Data Catalog entry groups and Cloud Storage buckets for fileset examples. They focus on configuring entries rather than provisioning the surrounding catalog structure.
To keep things focused, common entry patterns are omitted, including:
- BigQuery table integration (integratedSystem)
- Pub/Sub topic cataloging
- Tag attachment for flexible metadata
- Entry group creation and management
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
Entry Types & Configuration
type only for entries matching the EntryType enum (currently only FILESET is allowed). For all other entries, use userSpecifiedType with a custom value like my_custom_type.linkedResource is required for entries using the type property (like FILESET). For entries with userSpecifiedType, it’s optional and defaults to an empty string.type to FILESET and configure gcsFilesetSpec with filePatterns pointing to your GCS paths (e.g., gs://bucket/dir/*).Immutability & Updates
entryGroup, entryId, and type properties are immutable and cannot be modified after creation.Naming & Validation
Using a different cloud?
Explore analytics guides for other cloud providers: