Deploy GCP Cloud Firestore Databases

The gcp:firestore/database:Database resource, part of the Pulumi GCP provider, provisions a Cloud Firestore database: its mode (Native or Datastore), location, and operational features like encryption and recovery. This guide focuses on four capabilities: Native and Datastore mode selection, point-in-time recovery and deletion protection, customer-managed encryption with Cloud KMS, and Enterprise edition provisioning.

Firestore databases belong to a GCP project and require the Firestore API to be enabled. CMEK configurations depend on pre-existing KMS keys and IAM bindings. The examples are intentionally small. Combine them with your own project configuration and security policies.

Create the default database in Native mode

Most projects start with a single default database in Firestore Native mode, which provides real-time synchronization and mobile SDKs for document storage.

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

const database = new gcp.firestore.Database("database", {
    project: "my-project-name",
    name: "(default)",
    locationId: "nam5",
    type: "FIRESTORE_NATIVE",
});
import pulumi
import pulumi_gcp as gcp

database = gcp.firestore.Database("database",
    project="my-project-name",
    name="(default)",
    location_id="nam5",
    type="FIRESTORE_NATIVE")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := firestore.NewDatabase(ctx, "database", &firestore.DatabaseArgs{
			Project:    pulumi.String("my-project-name"),
			Name:       pulumi.String("(default)"),
			LocationId: pulumi.String("nam5"),
			Type:       pulumi.String("FIRESTORE_NATIVE"),
		})
		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 database = new Gcp.Firestore.Database("database", new()
    {
        Project = "my-project-name",
        Name = "(default)",
        LocationId = "nam5",
        Type = "FIRESTORE_NATIVE",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.firestore.Database;
import com.pulumi.gcp.firestore.DatabaseArgs;
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 database = new Database("database", DatabaseArgs.builder()
            .project("my-project-name")
            .name("(default)")
            .locationId("nam5")
            .type("FIRESTORE_NATIVE")
            .build());

    }
}
resources:
  database:
    type: gcp:firestore:Database
    properties:
      project: my-project-name
      name: (default)
      locationId: nam5
      type: FIRESTORE_NATIVE

The name property uses the special value “(default)” to create the project’s primary database. The type property set to “FIRESTORE_NATIVE” enables document and collection storage with real-time listeners. The locationId determines where data is stored; once set, it cannot be changed.

Configure concurrency, recovery, and deletion protection

Production databases often enable point-in-time recovery for data restoration, optimistic concurrency for write performance, and deletion protection to prevent accidental removal.

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

const database = new gcp.firestore.Database("database", {
    project: "my-project-name",
    name: "database-id",
    locationId: "nam5",
    type: "FIRESTORE_NATIVE",
    concurrencyMode: "OPTIMISTIC",
    appEngineIntegrationMode: "DISABLED",
    pointInTimeRecoveryEnablement: "POINT_IN_TIME_RECOVERY_ENABLED",
    deleteProtectionState: "DELETE_PROTECTION_ENABLED",
    deletionPolicy: "DELETE",
});
import pulumi
import pulumi_gcp as gcp

database = gcp.firestore.Database("database",
    project="my-project-name",
    name="database-id",
    location_id="nam5",
    type="FIRESTORE_NATIVE",
    concurrency_mode="OPTIMISTIC",
    app_engine_integration_mode="DISABLED",
    point_in_time_recovery_enablement="POINT_IN_TIME_RECOVERY_ENABLED",
    delete_protection_state="DELETE_PROTECTION_ENABLED",
    deletion_policy="DELETE")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := firestore.NewDatabase(ctx, "database", &firestore.DatabaseArgs{
			Project:                       pulumi.String("my-project-name"),
			Name:                          pulumi.String("database-id"),
			LocationId:                    pulumi.String("nam5"),
			Type:                          pulumi.String("FIRESTORE_NATIVE"),
			ConcurrencyMode:               pulumi.String("OPTIMISTIC"),
			AppEngineIntegrationMode:      pulumi.String("DISABLED"),
			PointInTimeRecoveryEnablement: pulumi.String("POINT_IN_TIME_RECOVERY_ENABLED"),
			DeleteProtectionState:         pulumi.String("DELETE_PROTECTION_ENABLED"),
			DeletionPolicy:                pulumi.String("DELETE"),
		})
		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 database = new Gcp.Firestore.Database("database", new()
    {
        Project = "my-project-name",
        Name = "database-id",
        LocationId = "nam5",
        Type = "FIRESTORE_NATIVE",
        ConcurrencyMode = "OPTIMISTIC",
        AppEngineIntegrationMode = "DISABLED",
        PointInTimeRecoveryEnablement = "POINT_IN_TIME_RECOVERY_ENABLED",
        DeleteProtectionState = "DELETE_PROTECTION_ENABLED",
        DeletionPolicy = "DELETE",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.firestore.Database;
import com.pulumi.gcp.firestore.DatabaseArgs;
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 database = new Database("database", DatabaseArgs.builder()
            .project("my-project-name")
            .name("database-id")
            .locationId("nam5")
            .type("FIRESTORE_NATIVE")
            .concurrencyMode("OPTIMISTIC")
            .appEngineIntegrationMode("DISABLED")
            .pointInTimeRecoveryEnablement("POINT_IN_TIME_RECOVERY_ENABLED")
            .deleteProtectionState("DELETE_PROTECTION_ENABLED")
            .deletionPolicy("DELETE")
            .build());

    }
}
resources:
  database:
    type: gcp:firestore:Database
    properties:
      project: my-project-name
      name: database-id
      locationId: nam5
      type: FIRESTORE_NATIVE
      concurrencyMode: OPTIMISTIC
      appEngineIntegrationMode: DISABLED
      pointInTimeRecoveryEnablement: POINT_IN_TIME_RECOVERY_ENABLED
      deleteProtectionState: DELETE_PROTECTION_ENABLED
      deletionPolicy: DELETE

When pointInTimeRecoveryEnablement is set to “POINT_IN_TIME_RECOVERY_ENABLED”, Firestore retains data versions for 7 days, allowing reads against any timestamp within that window. The concurrencyMode property controls transaction behavior: “OPTIMISTIC” allows concurrent writes with conflict detection. The deleteProtectionState property prevents accidental deletion when set to “DELETE_PROTECTION_ENABLED”.

Encrypt data with customer-managed keys

Organizations with compliance requirements often control encryption keys through Cloud KMS rather than relying on Google-managed encryption.

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

const project = gcp.organizations.getProject({});
const keyRing = new gcp.kms.KeyRing("key_ring", {
    name: "kms-key-ring",
    location: "us",
});
const cryptoKey = new gcp.kms.CryptoKey("crypto_key", {
    name: "kms-key",
    keyRing: keyRing.id,
    purpose: "ENCRYPT_DECRYPT",
});
const firestoreCmekKeyuser = new gcp.kms.CryptoKeyIAMBinding("firestore_cmek_keyuser", {
    cryptoKeyId: cryptoKey.id,
    role: "roles/cloudkms.cryptoKeyEncrypterDecrypter",
    members: [project.then(project => `serviceAccount:service-${project.number}@gcp-sa-firestore.iam.gserviceaccount.com`)],
});
const database = new gcp.firestore.Database("database", {
    project: "my-project-name",
    name: "cmek-database-id",
    locationId: "nam5",
    type: "FIRESTORE_NATIVE",
    concurrencyMode: "OPTIMISTIC",
    appEngineIntegrationMode: "DISABLED",
    pointInTimeRecoveryEnablement: "POINT_IN_TIME_RECOVERY_ENABLED",
    deleteProtectionState: "DELETE_PROTECTION_ENABLED",
    deletionPolicy: "DELETE",
    cmekConfig: {
        kmsKeyName: cryptoKey.id,
    },
}, {
    dependsOn: [firestoreCmekKeyuser],
});
import pulumi
import pulumi_gcp as gcp

project = gcp.organizations.get_project()
key_ring = gcp.kms.KeyRing("key_ring",
    name="kms-key-ring",
    location="us")
crypto_key = gcp.kms.CryptoKey("crypto_key",
    name="kms-key",
    key_ring=key_ring.id,
    purpose="ENCRYPT_DECRYPT")
firestore_cmek_keyuser = gcp.kms.CryptoKeyIAMBinding("firestore_cmek_keyuser",
    crypto_key_id=crypto_key.id,
    role="roles/cloudkms.cryptoKeyEncrypterDecrypter",
    members=[f"serviceAccount:service-{project.number}@gcp-sa-firestore.iam.gserviceaccount.com"])
database = gcp.firestore.Database("database",
    project="my-project-name",
    name="cmek-database-id",
    location_id="nam5",
    type="FIRESTORE_NATIVE",
    concurrency_mode="OPTIMISTIC",
    app_engine_integration_mode="DISABLED",
    point_in_time_recovery_enablement="POINT_IN_TIME_RECOVERY_ENABLED",
    delete_protection_state="DELETE_PROTECTION_ENABLED",
    deletion_policy="DELETE",
    cmek_config={
        "kms_key_name": crypto_key.id,
    },
    opts = pulumi.ResourceOptions(depends_on=[firestore_cmek_keyuser]))
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/firestore"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/kms"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
		if err != nil {
			return err
		}
		keyRing, err := kms.NewKeyRing(ctx, "key_ring", &kms.KeyRingArgs{
			Name:     pulumi.String("kms-key-ring"),
			Location: pulumi.String("us"),
		})
		if err != nil {
			return err
		}
		cryptoKey, err := kms.NewCryptoKey(ctx, "crypto_key", &kms.CryptoKeyArgs{
			Name:    pulumi.String("kms-key"),
			KeyRing: keyRing.ID(),
			Purpose: pulumi.String("ENCRYPT_DECRYPT"),
		})
		if err != nil {
			return err
		}
		firestoreCmekKeyuser, err := kms.NewCryptoKeyIAMBinding(ctx, "firestore_cmek_keyuser", &kms.CryptoKeyIAMBindingArgs{
			CryptoKeyId: cryptoKey.ID(),
			Role:        pulumi.String("roles/cloudkms.cryptoKeyEncrypterDecrypter"),
			Members: pulumi.StringArray{
				pulumi.Sprintf("serviceAccount:service-%v@gcp-sa-firestore.iam.gserviceaccount.com", project.Number),
			},
		})
		if err != nil {
			return err
		}
		_, err = firestore.NewDatabase(ctx, "database", &firestore.DatabaseArgs{
			Project:                       pulumi.String("my-project-name"),
			Name:                          pulumi.String("cmek-database-id"),
			LocationId:                    pulumi.String("nam5"),
			Type:                          pulumi.String("FIRESTORE_NATIVE"),
			ConcurrencyMode:               pulumi.String("OPTIMISTIC"),
			AppEngineIntegrationMode:      pulumi.String("DISABLED"),
			PointInTimeRecoveryEnablement: pulumi.String("POINT_IN_TIME_RECOVERY_ENABLED"),
			DeleteProtectionState:         pulumi.String("DELETE_PROTECTION_ENABLED"),
			DeletionPolicy:                pulumi.String("DELETE"),
			CmekConfig: &firestore.DatabaseCmekConfigArgs{
				KmsKeyName: cryptoKey.ID(),
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			firestoreCmekKeyuser,
		}))
		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 project = Gcp.Organizations.GetProject.Invoke();

    var keyRing = new Gcp.Kms.KeyRing("key_ring", new()
    {
        Name = "kms-key-ring",
        Location = "us",
    });

    var cryptoKey = new Gcp.Kms.CryptoKey("crypto_key", new()
    {
        Name = "kms-key",
        KeyRing = keyRing.Id,
        Purpose = "ENCRYPT_DECRYPT",
    });

    var firestoreCmekKeyuser = new Gcp.Kms.CryptoKeyIAMBinding("firestore_cmek_keyuser", new()
    {
        CryptoKeyId = cryptoKey.Id,
        Role = "roles/cloudkms.cryptoKeyEncrypterDecrypter",
        Members = new[]
        {
            $"serviceAccount:service-{project.Apply(getProjectResult => getProjectResult.Number)}@gcp-sa-firestore.iam.gserviceaccount.com",
        },
    });

    var database = new Gcp.Firestore.Database("database", new()
    {
        Project = "my-project-name",
        Name = "cmek-database-id",
        LocationId = "nam5",
        Type = "FIRESTORE_NATIVE",
        ConcurrencyMode = "OPTIMISTIC",
        AppEngineIntegrationMode = "DISABLED",
        PointInTimeRecoveryEnablement = "POINT_IN_TIME_RECOVERY_ENABLED",
        DeleteProtectionState = "DELETE_PROTECTION_ENABLED",
        DeletionPolicy = "DELETE",
        CmekConfig = new Gcp.Firestore.Inputs.DatabaseCmekConfigArgs
        {
            KmsKeyName = cryptoKey.Id,
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            firestoreCmekKeyuser,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.kms.KeyRing;
import com.pulumi.gcp.kms.KeyRingArgs;
import com.pulumi.gcp.kms.CryptoKey;
import com.pulumi.gcp.kms.CryptoKeyArgs;
import com.pulumi.gcp.kms.CryptoKeyIAMBinding;
import com.pulumi.gcp.kms.CryptoKeyIAMBindingArgs;
import com.pulumi.gcp.firestore.Database;
import com.pulumi.gcp.firestore.DatabaseArgs;
import com.pulumi.gcp.firestore.inputs.DatabaseCmekConfigArgs;
import com.pulumi.resources.CustomResourceOptions;
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) {
        final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
            .build());

        var keyRing = new KeyRing("keyRing", KeyRingArgs.builder()
            .name("kms-key-ring")
            .location("us")
            .build());

        var cryptoKey = new CryptoKey("cryptoKey", CryptoKeyArgs.builder()
            .name("kms-key")
            .keyRing(keyRing.id())
            .purpose("ENCRYPT_DECRYPT")
            .build());

        var firestoreCmekKeyuser = new CryptoKeyIAMBinding("firestoreCmekKeyuser", CryptoKeyIAMBindingArgs.builder()
            .cryptoKeyId(cryptoKey.id())
            .role("roles/cloudkms.cryptoKeyEncrypterDecrypter")
            .members(String.format("serviceAccount:service-%s@gcp-sa-firestore.iam.gserviceaccount.com", project.number()))
            .build());

        var database = new Database("database", DatabaseArgs.builder()
            .project("my-project-name")
            .name("cmek-database-id")
            .locationId("nam5")
            .type("FIRESTORE_NATIVE")
            .concurrencyMode("OPTIMISTIC")
            .appEngineIntegrationMode("DISABLED")
            .pointInTimeRecoveryEnablement("POINT_IN_TIME_RECOVERY_ENABLED")
            .deleteProtectionState("DELETE_PROTECTION_ENABLED")
            .deletionPolicy("DELETE")
            .cmekConfig(DatabaseCmekConfigArgs.builder()
                .kmsKeyName(cryptoKey.id())
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(firestoreCmekKeyuser)
                .build());

    }
}
resources:
  database:
    type: gcp:firestore:Database
    properties:
      project: my-project-name
      name: cmek-database-id
      locationId: nam5
      type: FIRESTORE_NATIVE
      concurrencyMode: OPTIMISTIC
      appEngineIntegrationMode: DISABLED
      pointInTimeRecoveryEnablement: POINT_IN_TIME_RECOVERY_ENABLED
      deleteProtectionState: DELETE_PROTECTION_ENABLED
      deletionPolicy: DELETE
      cmekConfig:
        kmsKeyName: ${cryptoKey.id}
    options:
      dependsOn:
        - ${firestoreCmekKeyuser}
  cryptoKey:
    type: gcp:kms:CryptoKey
    name: crypto_key
    properties:
      name: kms-key
      keyRing: ${keyRing.id}
      purpose: ENCRYPT_DECRYPT
  keyRing:
    type: gcp:kms:KeyRing
    name: key_ring
    properties:
      name: kms-key-ring
      location: us
  firestoreCmekKeyuser:
    type: gcp:kms:CryptoKeyIAMBinding
    name: firestore_cmek_keyuser
    properties:
      cryptoKeyId: ${cryptoKey.id}
      role: roles/cloudkms.cryptoKeyEncrypterDecrypter
      members:
        - serviceAccount:service-${project.number}@gcp-sa-firestore.iam.gserviceaccount.com
variables:
  project:
    fn::invoke:
      function: gcp:organizations:getProject
      arguments: {}

The cmekConfig block references a KMS crypto key for encryption. Before creating the database, you must grant the Firestore service account the cryptoKeyEncrypterDecrypter role on the key. The dependsOn property ensures the IAM binding completes before database creation. The KMS key location must be compatible with the database location.

Create the default database in Datastore mode

Applications migrating from Cloud Datastore or requiring Datastore’s entity-based model can provision databases in Datastore mode for backward compatibility.

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

const datastoreModeDatabase = new gcp.firestore.Database("datastore_mode_database", {
    project: "my-project-name",
    name: "(default)",
    locationId: "nam5",
    type: "DATASTORE_MODE",
});
import pulumi
import pulumi_gcp as gcp

datastore_mode_database = gcp.firestore.Database("datastore_mode_database",
    project="my-project-name",
    name="(default)",
    location_id="nam5",
    type="DATASTORE_MODE")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := firestore.NewDatabase(ctx, "datastore_mode_database", &firestore.DatabaseArgs{
			Project:    pulumi.String("my-project-name"),
			Name:       pulumi.String("(default)"),
			LocationId: pulumi.String("nam5"),
			Type:       pulumi.String("DATASTORE_MODE"),
		})
		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 datastoreModeDatabase = new Gcp.Firestore.Database("datastore_mode_database", new()
    {
        Project = "my-project-name",
        Name = "(default)",
        LocationId = "nam5",
        Type = "DATASTORE_MODE",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.firestore.Database;
import com.pulumi.gcp.firestore.DatabaseArgs;
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 datastoreModeDatabase = new Database("datastoreModeDatabase", DatabaseArgs.builder()
            .project("my-project-name")
            .name("(default)")
            .locationId("nam5")
            .type("DATASTORE_MODE")
            .build());

    }
}
resources:
  datastoreModeDatabase:
    type: gcp:firestore:Database
    name: datastore_mode_database
    properties:
      project: my-project-name
      name: (default)
      locationId: nam5
      type: DATASTORE_MODE

Setting type to “DATASTORE_MODE” creates a database that uses the Datastore API and entity model instead of Firestore’s document model. This mode is useful for applications already built on Datastore or requiring its specific features like entity groups.

Provision an Enterprise edition database

High-throughput applications requiring enhanced performance and SLA guarantees can use the Enterprise edition, which provides higher limits and dedicated capacity.

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

const enterprise_db = new gcp.firestore.Database("enterprise-db", {
    project: "my-project-name",
    name: "database-id",
    locationId: "nam5",
    type: "FIRESTORE_NATIVE",
    databaseEdition: "ENTERPRISE",
    deletionPolicy: "DELETE",
});
import pulumi
import pulumi_gcp as gcp

enterprise_db = gcp.firestore.Database("enterprise-db",
    project="my-project-name",
    name="database-id",
    location_id="nam5",
    type="FIRESTORE_NATIVE",
    database_edition="ENTERPRISE",
    deletion_policy="DELETE")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := firestore.NewDatabase(ctx, "enterprise-db", &firestore.DatabaseArgs{
			Project:         pulumi.String("my-project-name"),
			Name:            pulumi.String("database-id"),
			LocationId:      pulumi.String("nam5"),
			Type:            pulumi.String("FIRESTORE_NATIVE"),
			DatabaseEdition: pulumi.String("ENTERPRISE"),
			DeletionPolicy:  pulumi.String("DELETE"),
		})
		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 enterprise_db = new Gcp.Firestore.Database("enterprise-db", new()
    {
        Project = "my-project-name",
        Name = "database-id",
        LocationId = "nam5",
        Type = "FIRESTORE_NATIVE",
        DatabaseEdition = "ENTERPRISE",
        DeletionPolicy = "DELETE",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.firestore.Database;
import com.pulumi.gcp.firestore.DatabaseArgs;
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 enterprise_db = new Database("enterprise-db", DatabaseArgs.builder()
            .project("my-project-name")
            .name("database-id")
            .locationId("nam5")
            .type("FIRESTORE_NATIVE")
            .databaseEdition("ENTERPRISE")
            .deletionPolicy("DELETE")
            .build());

    }
}
resources:
  enterprise-db:
    type: gcp:firestore:Database
    properties:
      project: my-project-name
      name: database-id
      locationId: nam5
      type: FIRESTORE_NATIVE
      databaseEdition: ENTERPRISE
      deletionPolicy: DELETE

The databaseEdition property set to “ENTERPRISE” provisions a database with higher throughput limits and dedicated capacity. This edition is immutable once set and requires explicit configuration at creation time.

Beyond these examples

These snippets focus on specific database-level features: Native and Datastore mode databases, point-in-time recovery and deletion protection, customer-managed encryption keys, and Enterprise edition provisioning. They’re intentionally minimal rather than full data platform deployments.

The examples may reference pre-existing infrastructure such as GCP projects with Firestore API enabled, and KMS key rings, crypto keys, and IAM bindings for Firestore service accounts (for CMEK examples). They focus on configuring the database rather than provisioning the surrounding infrastructure.

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

  • Resource manager tags (tags property)
  • App Engine integration mode configuration
  • Concurrency mode selection (OPTIMISTIC vs PESSIMISTIC)
  • Database naming constraints and validation

These omissions are intentional: the goal is to illustrate how each database feature is wired, not provide drop-in data platform modules. See the Firestore Database resource reference for all available configuration options.

Let's deploy GCP Cloud Firestore Databases

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Resource Selection & Setup
Should I use gcp.firestore.Database or gcp.appengine.Application for Firestore?
Use gcp.appengine.Application if you need Firestore with App Engine. Use gcp.firestore.Database for standalone Firestore databases. If migrating from gcp.appengine.Application to gcp.firestore.Database, follow the migration instructions in the GCP documentation.
What's the difference between FIRESTORE_NATIVE and DATASTORE_MODE?
These are the two database types available via the type property. FIRESTORE_NATIVE provides the full Firestore feature set, while DATASTORE_MODE provides Datastore compatibility. See the GCP documentation for guidance on choosing between them.
Database Configuration
Can I use '(default)' as a database name?
Yes, the special name (default) creates the default database for your project, as shown in the default database examples.
What are the naming rules for Firestore databases?
Database names must be 4-63 characters, start with a letter, end with a letter or number, and contain only lowercase letters, numbers, and hyphens. Names cannot be UUID-like (format: [0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}). The special name (default) is also valid.
What's the difference between STANDARD and ENTERPRISE database editions?
The databaseEdition property accepts STANDARD or ENTERPRISE values. This property is immutable after creation, so choose carefully during initial setup.
Immutability & Updates
What properties can't I change after creating a database?
The following properties are immutable and will force resource replacement if changed: databaseEdition, locationId, name, project, cmekConfig, and tags.
What happens if I modify the tags property?
The tags property is immutable and causes resource replacement when modified. To apply tags to an existing database without replacement, use the gcp.tags.TagValue resource instead.
Encryption & Security
How do I set up customer-managed encryption (CMEK) for my database?
Configure cmekConfig with your KMS key ID, create an IAM binding granting the Firestore service account (service-{project-number}@gcp-sa-firestore.iam.gserviceaccount.com) the roles/cloudkms.cryptoKeyEncrypterDecrypter role, and use dependsOn to ensure the IAM binding is created before the database.
Point-in-Time Recovery
How does point-in-time recovery work?
When pointInTimeRecoveryEnablement is set to POINT_IN_TIME_RECOVERY_ENABLED, you get 7-day retention with reads supported on any timestamp within the past hour and 1-minute snapshots beyond 1 hour. When disabled (the default), you only get 1-hour retention. Use versionRetentionPeriod and earliestVersionTime to determine supported versions.

Using a different cloud?

Explore database guides for other cloud providers: