Deploy GCP Filestore Instances

The gcp:filestore/instance:Instance resource, part of the Pulumi GCP provider, provisions a Filestore instance that provides managed NFS file shares for GCP workloads. This guide focuses on three capabilities: basic instance creation with tier selection, NFS export options for access control, and customer-managed encryption keys.

Filestore instances connect to VPC networks through peering, and encryption examples require Cloud KMS key rings and crypto keys. The examples are intentionally small. Combine them with your own VPC configuration and access policies.

Create a basic instance with HDD storage

Most deployments start with a basic instance that provides cost-effective NFS storage for general-purpose file sharing.

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

const instance = new gcp.filestore.Instance("instance", {
    name: "test-instance",
    location: "us-central1-b",
    tier: "BASIC_HDD",
    fileShares: {
        capacityGb: 1024,
        name: "share1",
    },
    networks: [{
        network: "default",
        modes: ["MODE_IPV4"],
    }],
});
import pulumi
import pulumi_gcp as gcp

instance = gcp.filestore.Instance("instance",
    name="test-instance",
    location="us-central1-b",
    tier="BASIC_HDD",
    file_shares={
        "capacity_gb": 1024,
        "name": "share1",
    },
    networks=[{
        "network": "default",
        "modes": ["MODE_IPV4"],
    }])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := filestore.NewInstance(ctx, "instance", &filestore.InstanceArgs{
			Name:     pulumi.String("test-instance"),
			Location: pulumi.String("us-central1-b"),
			Tier:     pulumi.String("BASIC_HDD"),
			FileShares: &filestore.InstanceFileSharesArgs{
				CapacityGb: pulumi.Int(1024),
				Name:       pulumi.String("share1"),
			},
			Networks: filestore.InstanceNetworkArray{
				&filestore.InstanceNetworkArgs{
					Network: pulumi.String("default"),
					Modes: pulumi.StringArray{
						pulumi.String("MODE_IPV4"),
					},
				},
			},
		})
		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 instance = new Gcp.Filestore.Instance("instance", new()
    {
        Name = "test-instance",
        Location = "us-central1-b",
        Tier = "BASIC_HDD",
        FileShares = new Gcp.Filestore.Inputs.InstanceFileSharesArgs
        {
            CapacityGb = 1024,
            Name = "share1",
        },
        Networks = new[]
        {
            new Gcp.Filestore.Inputs.InstanceNetworkArgs
            {
                Network = "default",
                Modes = new[]
                {
                    "MODE_IPV4",
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.filestore.Instance;
import com.pulumi.gcp.filestore.InstanceArgs;
import com.pulumi.gcp.filestore.inputs.InstanceFileSharesArgs;
import com.pulumi.gcp.filestore.inputs.InstanceNetworkArgs;
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 instance = new Instance("instance", InstanceArgs.builder()
            .name("test-instance")
            .location("us-central1-b")
            .tier("BASIC_HDD")
            .fileShares(InstanceFileSharesArgs.builder()
                .capacityGb(1024)
                .name("share1")
                .build())
            .networks(InstanceNetworkArgs.builder()
                .network("default")
                .modes("MODE_IPV4")
                .build())
            .build());

    }
}
resources:
  instance:
    type: gcp:filestore:Instance
    properties:
      name: test-instance
      location: us-central1-b
      tier: BASIC_HDD
      fileShares:
        capacityGb: 1024
        name: share1
      networks:
        - network: default
          modes:
            - MODE_IPV4

The fileShares property defines the share name and capacity in gigabytes. The tier property controls performance and features; BASIC_HDD offers lower-cost spinning disk storage. The networks property connects the instance to your VPC, where clients mount the share using the instance’s IP address. The location property determines where the instance runs; for BASIC tiers, this must be a zone.

Control access with NFS export options

Production workloads often need different IP ranges to access shares with different permissions.

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

const instance = new gcp.filestore.Instance("instance", {
    name: "test-instance",
    location: "us-central1-b",
    tier: "BASIC_SSD",
    fileShares: {
        capacityGb: 2560,
        name: "share1",
        nfsExportOptions: [
            {
                ipRanges: ["10.0.0.0/24"],
                accessMode: "READ_WRITE",
                squashMode: "NO_ROOT_SQUASH",
            },
            {
                ipRanges: ["10.10.0.0/24"],
                accessMode: "READ_ONLY",
                squashMode: "ROOT_SQUASH",
                anonUid: 123,
                anonGid: 456,
            },
        ],
    },
    networks: [{
        network: "default",
        modes: ["MODE_IPV4"],
        connectMode: "DIRECT_PEERING",
    }],
});
import pulumi
import pulumi_gcp as gcp

instance = gcp.filestore.Instance("instance",
    name="test-instance",
    location="us-central1-b",
    tier="BASIC_SSD",
    file_shares={
        "capacity_gb": 2560,
        "name": "share1",
        "nfs_export_options": [
            {
                "ip_ranges": ["10.0.0.0/24"],
                "access_mode": "READ_WRITE",
                "squash_mode": "NO_ROOT_SQUASH",
            },
            {
                "ip_ranges": ["10.10.0.0/24"],
                "access_mode": "READ_ONLY",
                "squash_mode": "ROOT_SQUASH",
                "anon_uid": 123,
                "anon_gid": 456,
            },
        ],
    },
    networks=[{
        "network": "default",
        "modes": ["MODE_IPV4"],
        "connect_mode": "DIRECT_PEERING",
    }])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := filestore.NewInstance(ctx, "instance", &filestore.InstanceArgs{
			Name:     pulumi.String("test-instance"),
			Location: pulumi.String("us-central1-b"),
			Tier:     pulumi.String("BASIC_SSD"),
			FileShares: &filestore.InstanceFileSharesArgs{
				CapacityGb: pulumi.Int(2560),
				Name:       pulumi.String("share1"),
				NfsExportOptions: filestore.InstanceFileSharesNfsExportOptionArray{
					&filestore.InstanceFileSharesNfsExportOptionArgs{
						IpRanges: pulumi.StringArray{
							pulumi.String("10.0.0.0/24"),
						},
						AccessMode: pulumi.String("READ_WRITE"),
						SquashMode: pulumi.String("NO_ROOT_SQUASH"),
					},
					&filestore.InstanceFileSharesNfsExportOptionArgs{
						IpRanges: pulumi.StringArray{
							pulumi.String("10.10.0.0/24"),
						},
						AccessMode: pulumi.String("READ_ONLY"),
						SquashMode: pulumi.String("ROOT_SQUASH"),
						AnonUid:    pulumi.Int(123),
						AnonGid:    pulumi.Int(456),
					},
				},
			},
			Networks: filestore.InstanceNetworkArray{
				&filestore.InstanceNetworkArgs{
					Network: pulumi.String("default"),
					Modes: pulumi.StringArray{
						pulumi.String("MODE_IPV4"),
					},
					ConnectMode: pulumi.String("DIRECT_PEERING"),
				},
			},
		})
		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 instance = new Gcp.Filestore.Instance("instance", new()
    {
        Name = "test-instance",
        Location = "us-central1-b",
        Tier = "BASIC_SSD",
        FileShares = new Gcp.Filestore.Inputs.InstanceFileSharesArgs
        {
            CapacityGb = 2560,
            Name = "share1",
            NfsExportOptions = new[]
            {
                new Gcp.Filestore.Inputs.InstanceFileSharesNfsExportOptionArgs
                {
                    IpRanges = new[]
                    {
                        "10.0.0.0/24",
                    },
                    AccessMode = "READ_WRITE",
                    SquashMode = "NO_ROOT_SQUASH",
                },
                new Gcp.Filestore.Inputs.InstanceFileSharesNfsExportOptionArgs
                {
                    IpRanges = new[]
                    {
                        "10.10.0.0/24",
                    },
                    AccessMode = "READ_ONLY",
                    SquashMode = "ROOT_SQUASH",
                    AnonUid = 123,
                    AnonGid = 456,
                },
            },
        },
        Networks = new[]
        {
            new Gcp.Filestore.Inputs.InstanceNetworkArgs
            {
                Network = "default",
                Modes = new[]
                {
                    "MODE_IPV4",
                },
                ConnectMode = "DIRECT_PEERING",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.filestore.Instance;
import com.pulumi.gcp.filestore.InstanceArgs;
import com.pulumi.gcp.filestore.inputs.InstanceFileSharesArgs;
import com.pulumi.gcp.filestore.inputs.InstanceNetworkArgs;
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 instance = new Instance("instance", InstanceArgs.builder()
            .name("test-instance")
            .location("us-central1-b")
            .tier("BASIC_SSD")
            .fileShares(InstanceFileSharesArgs.builder()
                .capacityGb(2560)
                .name("share1")
                .nfsExportOptions(                
                    InstanceFileSharesNfsExportOptionArgs.builder()
                        .ipRanges("10.0.0.0/24")
                        .accessMode("READ_WRITE")
                        .squashMode("NO_ROOT_SQUASH")
                        .build(),
                    InstanceFileSharesNfsExportOptionArgs.builder()
                        .ipRanges("10.10.0.0/24")
                        .accessMode("READ_ONLY")
                        .squashMode("ROOT_SQUASH")
                        .anonUid(123)
                        .anonGid(456)
                        .build())
                .build())
            .networks(InstanceNetworkArgs.builder()
                .network("default")
                .modes("MODE_IPV4")
                .connectMode("DIRECT_PEERING")
                .build())
            .build());

    }
}
resources:
  instance:
    type: gcp:filestore:Instance
    properties:
      name: test-instance
      location: us-central1-b
      tier: BASIC_SSD
      fileShares:
        capacityGb: 2560
        name: share1
        nfsExportOptions:
          - ipRanges:
              - 10.0.0.0/24
            accessMode: READ_WRITE
            squashMode: NO_ROOT_SQUASH
          - ipRanges:
              - 10.10.0.0/24
            accessMode: READ_ONLY
            squashMode: ROOT_SQUASH
            anonUid: 123
            anonGid: 456
      networks:
        - network: default
          modes:
            - MODE_IPV4
          connectMode: DIRECT_PEERING

NFS export options define which clients can mount the share and what they can do. Each entry in nfsExportOptions specifies ipRanges (client networks), accessMode (READ_WRITE or READ_ONLY), and squashMode (how root user access is handled). The NO_ROOT_SQUASH mode preserves root privileges, while ROOT_SQUASH maps root to an anonymous user. The anonUid and anonGid properties set the anonymous user identity for squashed access.

Encrypt data with customer-managed keys

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

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

const filestoreKeyring = new gcp.kms.KeyRing("filestore_keyring", {
    name: "filestore-keyring",
    location: "us-central1",
});
const filestoreKey = new gcp.kms.CryptoKey("filestore_key", {
    name: "filestore-key",
    keyRing: filestoreKeyring.id,
});
const instance = new gcp.filestore.Instance("instance", {
    name: "test-instance",
    location: "us-central1",
    tier: "ENTERPRISE",
    fileShares: {
        capacityGb: 1024,
        name: "share1",
    },
    networks: [{
        network: "default",
        modes: ["MODE_IPV4"],
    }],
    kmsKeyName: filestoreKey.id,
});
import pulumi
import pulumi_gcp as gcp

filestore_keyring = gcp.kms.KeyRing("filestore_keyring",
    name="filestore-keyring",
    location="us-central1")
filestore_key = gcp.kms.CryptoKey("filestore_key",
    name="filestore-key",
    key_ring=filestore_keyring.id)
instance = gcp.filestore.Instance("instance",
    name="test-instance",
    location="us-central1",
    tier="ENTERPRISE",
    file_shares={
        "capacity_gb": 1024,
        "name": "share1",
    },
    networks=[{
        "network": "default",
        "modes": ["MODE_IPV4"],
    }],
    kms_key_name=filestore_key.id)
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		filestoreKeyring, err := kms.NewKeyRing(ctx, "filestore_keyring", &kms.KeyRingArgs{
			Name:     pulumi.String("filestore-keyring"),
			Location: pulumi.String("us-central1"),
		})
		if err != nil {
			return err
		}
		filestoreKey, err := kms.NewCryptoKey(ctx, "filestore_key", &kms.CryptoKeyArgs{
			Name:    pulumi.String("filestore-key"),
			KeyRing: filestoreKeyring.ID(),
		})
		if err != nil {
			return err
		}
		_, err = filestore.NewInstance(ctx, "instance", &filestore.InstanceArgs{
			Name:     pulumi.String("test-instance"),
			Location: pulumi.String("us-central1"),
			Tier:     pulumi.String("ENTERPRISE"),
			FileShares: &filestore.InstanceFileSharesArgs{
				CapacityGb: pulumi.Int(1024),
				Name:       pulumi.String("share1"),
			},
			Networks: filestore.InstanceNetworkArray{
				&filestore.InstanceNetworkArgs{
					Network: pulumi.String("default"),
					Modes: pulumi.StringArray{
						pulumi.String("MODE_IPV4"),
					},
				},
			},
			KmsKeyName: filestoreKey.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 filestoreKeyring = new Gcp.Kms.KeyRing("filestore_keyring", new()
    {
        Name = "filestore-keyring",
        Location = "us-central1",
    });

    var filestoreKey = new Gcp.Kms.CryptoKey("filestore_key", new()
    {
        Name = "filestore-key",
        KeyRing = filestoreKeyring.Id,
    });

    var instance = new Gcp.Filestore.Instance("instance", new()
    {
        Name = "test-instance",
        Location = "us-central1",
        Tier = "ENTERPRISE",
        FileShares = new Gcp.Filestore.Inputs.InstanceFileSharesArgs
        {
            CapacityGb = 1024,
            Name = "share1",
        },
        Networks = new[]
        {
            new Gcp.Filestore.Inputs.InstanceNetworkArgs
            {
                Network = "default",
                Modes = new[]
                {
                    "MODE_IPV4",
                },
            },
        },
        KmsKeyName = filestoreKey.Id,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
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.filestore.Instance;
import com.pulumi.gcp.filestore.InstanceArgs;
import com.pulumi.gcp.filestore.inputs.InstanceFileSharesArgs;
import com.pulumi.gcp.filestore.inputs.InstanceNetworkArgs;
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 filestoreKeyring = new KeyRing("filestoreKeyring", KeyRingArgs.builder()
            .name("filestore-keyring")
            .location("us-central1")
            .build());

        var filestoreKey = new CryptoKey("filestoreKey", CryptoKeyArgs.builder()
            .name("filestore-key")
            .keyRing(filestoreKeyring.id())
            .build());

        var instance = new Instance("instance", InstanceArgs.builder()
            .name("test-instance")
            .location("us-central1")
            .tier("ENTERPRISE")
            .fileShares(InstanceFileSharesArgs.builder()
                .capacityGb(1024)
                .name("share1")
                .build())
            .networks(InstanceNetworkArgs.builder()
                .network("default")
                .modes("MODE_IPV4")
                .build())
            .kmsKeyName(filestoreKey.id())
            .build());

    }
}
resources:
  instance:
    type: gcp:filestore:Instance
    properties:
      name: test-instance
      location: us-central1
      tier: ENTERPRISE
      fileShares:
        capacityGb: 1024
        name: share1
      networks:
        - network: default
          modes:
            - MODE_IPV4
      kmsKeyName: ${filestoreKey.id}
  filestoreKeyring:
    type: gcp:kms:KeyRing
    name: filestore_keyring
    properties:
      name: filestore-keyring
      location: us-central1
  filestoreKey:
    type: gcp:kms:CryptoKey
    name: filestore_key
    properties:
      name: filestore-key
      keyRing: ${filestoreKeyring.id}

The kmsKeyName property references a Cloud KMS crypto key that Filestore uses to encrypt data at rest. The ENTERPRISE tier is required for customer-managed encryption keys. The Filestore service account needs the cryptoKeyEncrypterDecrypter role on the key to perform encryption operations. This configuration extends the basic instance pattern with encryption control.

Beyond these examples

These snippets focus on specific Filestore instance features: tier selection and capacity sizing, NFS export options and access control, and customer-managed encryption keys. They’re intentionally minimal rather than full storage solutions.

The examples rely on pre-existing infrastructure such as VPC networks with Filestore peering configured, and Cloud KMS key rings and crypto keys for encryption examples. They focus on configuring the instance rather than provisioning the surrounding network and security infrastructure.

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

  • NFSv4.1 protocol configuration (protocol property)
  • Deletion protection (deletionProtectionEnabled)
  • Performance tuning (performanceConfig)
  • Replication configuration (initialReplication, desiredReplicaState)
  • Directory Services integration for NFSv4.1

These omissions are intentional: the goal is to illustrate how each Filestore feature is wired, not provide drop-in storage modules. See the Filestore Instance resource reference for all available configuration options.

Let's deploy GCP Filestore Instances

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 properties can't be changed after creating a Filestore instance?
Several properties are immutable: location, networks, tier, project, protocol, kmsKeyName, initialReplication, and tags. Changing these requires recreating the instance.
What happens if I modify the tags on an existing instance?
Modifying tags after creation triggers resource replacement (recreation). To apply tags to existing instances without recreation, use the gcp.tags.TagValue resource instead.
Can I change replication settings after initial setup?
No, initialReplication cannot be updated once set. Specify this only on the replica instance, indicating the active instance as peerInstance.
Can I add multiple networks or file shares to an instance?
No, only a single network and a single file share are supported per instance.
Network & Access Control
How do I control which IP ranges can access my NFS share?

Configure nfsExportOptions within fileShares with:

  • ipRanges - allowed IP ranges
  • accessMode - READ_WRITE or READ_ONLY
  • squashMode - NO_ROOT_SQUASH or ROOT_SQUASH
  • Optional: anonUid and anonGid for anonymous access
How do I connect a Filestore instance to my VPC?
Set the networks property with your VPC network name and connection modes (e.g., MODE_IPV4). You can optionally specify connectMode as DIRECT_PEERING.
Storage & Protocols
Can I use NFSv4.1 instead of the default NFSv3?
Yes, set protocol to NFS_V4_1. This protocol works with HIGH_SCALE_SSD, ZONAL, REGIONAL, and ENTERPRISE tiers. The default is NFS_V3.
When can I use Directory Services configuration?
Directory Services (directoryServices) should only be configured when protocol is set to NFS_V4_1.
What storage tiers are available?
Available tiers: STANDARD, PREMIUM, BASIC_HDD, BASIC_SSD, HIGH_SCALE_SSD, ZONAL, REGIONAL, and ENTERPRISE. The tier is immutable after creation.
Security & Encryption
How do I encrypt my Filestore instance with a customer-managed key?
Set kmsKeyName to your KMS crypto key ID. This property is immutable, so it must be configured at creation time.
Metadata & Migration
Should I use zone or location for my instance?
Use location instead of zone. The zone property is deprecated and will be removed in a future release. For ENTERPRISE tier, location can be a region.
Why aren't all my labels showing up in the labels field?
The labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels to see all labels present on the resource in GCP.

Using a different cloud?

Explore storage guides for other cloud providers: