The gcp:vertex/aiFeatureStore:AiFeatureStore resource, part of the Pulumi GCP provider, provisions a Vertex AI Feature Store: a managed repository for storing, serving, and managing ML features for online and offline inference. This guide focuses on three capabilities: fixed and autoscaling serving capacity, feature value TTL configuration, and encryption setup.
Feature stores require KMS keys for encryption and run within a GCP project with Vertex AI enabled. The examples are intentionally small. Combine them with your own EntityType and Feature definitions, IAM policies, and monitoring configuration.
Create a feature store with fixed serving capacity
ML teams building feature stores for online serving typically start with a fixed node count to ensure predictable capacity and latency for model inference workloads.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const featurestore = new gcp.vertex.AiFeatureStore("featurestore", {
name: "terraform",
labels: {
foo: "bar",
},
region: "us-central1",
onlineServingConfig: {
fixedNodeCount: 2,
},
encryptionSpec: {
kmsKeyName: "kms-name",
},
forceDestroy: true,
});
import pulumi
import pulumi_gcp as gcp
featurestore = gcp.vertex.AiFeatureStore("featurestore",
name="terraform",
labels={
"foo": "bar",
},
region="us-central1",
online_serving_config={
"fixed_node_count": 2,
},
encryption_spec={
"kms_key_name": "kms-name",
},
force_destroy=True)
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/vertex"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := vertex.NewAiFeatureStore(ctx, "featurestore", &vertex.AiFeatureStoreArgs{
Name: pulumi.String("terraform"),
Labels: pulumi.StringMap{
"foo": pulumi.String("bar"),
},
Region: pulumi.String("us-central1"),
OnlineServingConfig: &vertex.AiFeatureStoreOnlineServingConfigArgs{
FixedNodeCount: pulumi.Int(2),
},
EncryptionSpec: &vertex.AiFeatureStoreEncryptionSpecArgs{
KmsKeyName: pulumi.String("kms-name"),
},
ForceDestroy: 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 featurestore = new Gcp.Vertex.AiFeatureStore("featurestore", new()
{
Name = "terraform",
Labels =
{
{ "foo", "bar" },
},
Region = "us-central1",
OnlineServingConfig = new Gcp.Vertex.Inputs.AiFeatureStoreOnlineServingConfigArgs
{
FixedNodeCount = 2,
},
EncryptionSpec = new Gcp.Vertex.Inputs.AiFeatureStoreEncryptionSpecArgs
{
KmsKeyName = "kms-name",
},
ForceDestroy = true,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.vertex.AiFeatureStore;
import com.pulumi.gcp.vertex.AiFeatureStoreArgs;
import com.pulumi.gcp.vertex.inputs.AiFeatureStoreOnlineServingConfigArgs;
import com.pulumi.gcp.vertex.inputs.AiFeatureStoreEncryptionSpecArgs;
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 featurestore = new AiFeatureStore("featurestore", AiFeatureStoreArgs.builder()
.name("terraform")
.labels(Map.of("foo", "bar"))
.region("us-central1")
.onlineServingConfig(AiFeatureStoreOnlineServingConfigArgs.builder()
.fixedNodeCount(2)
.build())
.encryptionSpec(AiFeatureStoreEncryptionSpecArgs.builder()
.kmsKeyName("kms-name")
.build())
.forceDestroy(true)
.build());
}
}
resources:
featurestore:
type: gcp:vertex:AiFeatureStore
properties:
name: terraform
labels:
foo: bar
region: us-central1
onlineServingConfig:
fixedNodeCount: 2
encryptionSpec:
kmsKeyName: kms-name
forceDestroy: true
The onlineServingConfig property controls how Vertex AI provisions serving infrastructure. Setting fixedNodeCount to 2 allocates two dedicated nodes for feature lookups, providing consistent latency for real-time predictions. The encryptionSpec property secures both online and offline storage using the specified KMS key.
Configure feature value retention with TTL
Feature stores often need to expire old feature values to manage storage costs and ensure models only access recent data.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const featurestore = new gcp.vertex.AiFeatureStore("featurestore", {
name: "terraform2",
labels: {
foo: "bar",
},
region: "us-central1",
onlineServingConfig: {
fixedNodeCount: 2,
},
encryptionSpec: {
kmsKeyName: "kms-name",
},
onlineStorageTtlDays: 30,
forceDestroy: true,
});
import pulumi
import pulumi_gcp as gcp
featurestore = gcp.vertex.AiFeatureStore("featurestore",
name="terraform2",
labels={
"foo": "bar",
},
region="us-central1",
online_serving_config={
"fixed_node_count": 2,
},
encryption_spec={
"kms_key_name": "kms-name",
},
online_storage_ttl_days=30,
force_destroy=True)
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/vertex"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := vertex.NewAiFeatureStore(ctx, "featurestore", &vertex.AiFeatureStoreArgs{
Name: pulumi.String("terraform2"),
Labels: pulumi.StringMap{
"foo": pulumi.String("bar"),
},
Region: pulumi.String("us-central1"),
OnlineServingConfig: &vertex.AiFeatureStoreOnlineServingConfigArgs{
FixedNodeCount: pulumi.Int(2),
},
EncryptionSpec: &vertex.AiFeatureStoreEncryptionSpecArgs{
KmsKeyName: pulumi.String("kms-name"),
},
OnlineStorageTtlDays: pulumi.Int(30),
ForceDestroy: 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 featurestore = new Gcp.Vertex.AiFeatureStore("featurestore", new()
{
Name = "terraform2",
Labels =
{
{ "foo", "bar" },
},
Region = "us-central1",
OnlineServingConfig = new Gcp.Vertex.Inputs.AiFeatureStoreOnlineServingConfigArgs
{
FixedNodeCount = 2,
},
EncryptionSpec = new Gcp.Vertex.Inputs.AiFeatureStoreEncryptionSpecArgs
{
KmsKeyName = "kms-name",
},
OnlineStorageTtlDays = 30,
ForceDestroy = true,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.vertex.AiFeatureStore;
import com.pulumi.gcp.vertex.AiFeatureStoreArgs;
import com.pulumi.gcp.vertex.inputs.AiFeatureStoreOnlineServingConfigArgs;
import com.pulumi.gcp.vertex.inputs.AiFeatureStoreEncryptionSpecArgs;
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 featurestore = new AiFeatureStore("featurestore", AiFeatureStoreArgs.builder()
.name("terraform2")
.labels(Map.of("foo", "bar"))
.region("us-central1")
.onlineServingConfig(AiFeatureStoreOnlineServingConfigArgs.builder()
.fixedNodeCount(2)
.build())
.encryptionSpec(AiFeatureStoreEncryptionSpecArgs.builder()
.kmsKeyName("kms-name")
.build())
.onlineStorageTtlDays(30)
.forceDestroy(true)
.build());
}
}
resources:
featurestore:
type: gcp:vertex:AiFeatureStore
properties:
name: terraform2
labels:
foo: bar
region: us-central1
onlineServingConfig:
fixedNodeCount: 2
encryptionSpec:
kmsKeyName: kms-name
onlineStorageTtlDays: 30
forceDestroy: true
The onlineStorageTtlDays property sets how long feature values remain in online storage before automatic removal. Here, features older than 30 days are deleted, reducing storage costs while keeping recent data available for inference. This extends the basic configuration with lifecycle management.
Enable autoscaling for variable workloads
Production workloads with fluctuating traffic patterns benefit from autoscaling to balance cost and performance automatically.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const featurestore = new gcp.vertex.AiFeatureStore("featurestore", {
name: "terraform3",
labels: {
foo: "bar",
},
region: "us-central1",
onlineServingConfig: {
scaling: {
minNodeCount: 2,
maxNodeCount: 10,
},
},
encryptionSpec: {
kmsKeyName: "kms-name",
},
forceDestroy: true,
});
import pulumi
import pulumi_gcp as gcp
featurestore = gcp.vertex.AiFeatureStore("featurestore",
name="terraform3",
labels={
"foo": "bar",
},
region="us-central1",
online_serving_config={
"scaling": {
"min_node_count": 2,
"max_node_count": 10,
},
},
encryption_spec={
"kms_key_name": "kms-name",
},
force_destroy=True)
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/vertex"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := vertex.NewAiFeatureStore(ctx, "featurestore", &vertex.AiFeatureStoreArgs{
Name: pulumi.String("terraform3"),
Labels: pulumi.StringMap{
"foo": pulumi.String("bar"),
},
Region: pulumi.String("us-central1"),
OnlineServingConfig: &vertex.AiFeatureStoreOnlineServingConfigArgs{
Scaling: &vertex.AiFeatureStoreOnlineServingConfigScalingArgs{
MinNodeCount: pulumi.Int(2),
MaxNodeCount: pulumi.Int(10),
},
},
EncryptionSpec: &vertex.AiFeatureStoreEncryptionSpecArgs{
KmsKeyName: pulumi.String("kms-name"),
},
ForceDestroy: 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 featurestore = new Gcp.Vertex.AiFeatureStore("featurestore", new()
{
Name = "terraform3",
Labels =
{
{ "foo", "bar" },
},
Region = "us-central1",
OnlineServingConfig = new Gcp.Vertex.Inputs.AiFeatureStoreOnlineServingConfigArgs
{
Scaling = new Gcp.Vertex.Inputs.AiFeatureStoreOnlineServingConfigScalingArgs
{
MinNodeCount = 2,
MaxNodeCount = 10,
},
},
EncryptionSpec = new Gcp.Vertex.Inputs.AiFeatureStoreEncryptionSpecArgs
{
KmsKeyName = "kms-name",
},
ForceDestroy = true,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.vertex.AiFeatureStore;
import com.pulumi.gcp.vertex.AiFeatureStoreArgs;
import com.pulumi.gcp.vertex.inputs.AiFeatureStoreOnlineServingConfigArgs;
import com.pulumi.gcp.vertex.inputs.AiFeatureStoreOnlineServingConfigScalingArgs;
import com.pulumi.gcp.vertex.inputs.AiFeatureStoreEncryptionSpecArgs;
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 featurestore = new AiFeatureStore("featurestore", AiFeatureStoreArgs.builder()
.name("terraform3")
.labels(Map.of("foo", "bar"))
.region("us-central1")
.onlineServingConfig(AiFeatureStoreOnlineServingConfigArgs.builder()
.scaling(AiFeatureStoreOnlineServingConfigScalingArgs.builder()
.minNodeCount(2)
.maxNodeCount(10)
.build())
.build())
.encryptionSpec(AiFeatureStoreEncryptionSpecArgs.builder()
.kmsKeyName("kms-name")
.build())
.forceDestroy(true)
.build());
}
}
resources:
featurestore:
type: gcp:vertex:AiFeatureStore
properties:
name: terraform3
labels:
foo: bar
region: us-central1
onlineServingConfig:
scaling:
minNodeCount: 2
maxNodeCount: 10
encryptionSpec:
kmsKeyName: kms-name
forceDestroy: true
Instead of fixedNodeCount, the scaling block defines minNodeCount and maxNodeCount boundaries. Vertex AI adjusts serving capacity between 2 and 10 nodes based on request volume, reducing costs during low-traffic periods while maintaining performance during spikes. This provides an alternative to fixed capacity for dynamic workloads.
Beyond these examples
These snippets focus on specific feature store-level features: fixed and autoscaling serving capacity, and encryption and TTL configuration. They’re intentionally minimal rather than full ML feature management systems.
The examples reference pre-existing infrastructure such as KMS encryption keys and a GCP project with Vertex AI API enabled. They focus on configuring the feature store container rather than defining the features themselves.
To keep things focused, common feature store patterns are omitted, including:
- EntityType and Feature definitions (managed separately)
- Offline storage configuration and batch serving
- Monitoring and alerting setup
- IAM permissions for feature store access
These omissions are intentional: the goal is to illustrate how each feature store capability is wired, not provide drop-in ML infrastructure modules. See the Vertex AI Feature Store resource reference for all available configuration options.
Let's create GCP Vertex AI Feature Stores
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Setup
name, project, and region properties are immutable. Changing any of these requires recreating the resource.[a-z0-9_]. The first character cannot be a number.Online Serving & Scaling
fixedNodeCount for a static number of serving nodes, or use scaling with minNodeCount and maxNodeCount for autoscaling between those limits.Data Management & Security
offlineStorageTtlDays for each EntityType under the featurestore.forceDestroy to true causes all associated EntityTypes and Features to be deleted when the featurestore is destroyed.encryptionSpec with a kmsKeyName to secure both online and offline data storage.Labels & Metadata
labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels to see all labels present on the resource.Using a different cloud?
Explore analytics guides for other cloud providers: