The gcp:healthcare/fhirStore:FhirStore resource, part of the Pulumi GCP provider, defines a FHIR store within a Healthcare dataset that stores and manages healthcare data conforming to FHIR standards (DSTU2, STU3, or R4). This guide focuses on three capabilities: Pub/Sub notifications for resource mutations, BigQuery streaming for analytics, and consent enforcement and validation controls.
FHIR stores belong to Healthcare datasets and may reference Pub/Sub topics or BigQuery datasets for notifications and streaming. The examples are intentionally small. Combine them with your own Healthcare datasets, notification infrastructure, and access policies.
Create a FHIR store with Pub/Sub notifications
Most FHIR deployments start with a basic store that tracks resource mutations through Pub/Sub notifications, enabling downstream systems to react to patient data changes.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const topic = new gcp.pubsub.Topic("topic", {name: "fhir-notifications"});
const dataset = new gcp.healthcare.Dataset("dataset", {
name: "example-dataset",
location: "us-central1",
});
const _default = new gcp.healthcare.FhirStore("default", {
name: "example-fhir-store",
dataset: dataset.id,
version: "R4",
complexDataTypeReferenceParsing: "DISABLED",
enableUpdateCreate: false,
disableReferentialIntegrity: false,
disableResourceVersioning: false,
enableHistoryImport: false,
defaultSearchHandlingStrict: false,
notificationConfigs: [{
pubsubTopic: topic.id,
}],
labels: {
label1: "labelvalue1",
},
});
import pulumi
import pulumi_gcp as gcp
topic = gcp.pubsub.Topic("topic", name="fhir-notifications")
dataset = gcp.healthcare.Dataset("dataset",
name="example-dataset",
location="us-central1")
default = gcp.healthcare.FhirStore("default",
name="example-fhir-store",
dataset=dataset.id,
version="R4",
complex_data_type_reference_parsing="DISABLED",
enable_update_create=False,
disable_referential_integrity=False,
disable_resource_versioning=False,
enable_history_import=False,
default_search_handling_strict=False,
notification_configs=[{
"pubsub_topic": topic.id,
}],
labels={
"label1": "labelvalue1",
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/healthcare"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/pubsub"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
topic, err := pubsub.NewTopic(ctx, "topic", &pubsub.TopicArgs{
Name: pulumi.String("fhir-notifications"),
})
if err != nil {
return err
}
dataset, err := healthcare.NewDataset(ctx, "dataset", &healthcare.DatasetArgs{
Name: pulumi.String("example-dataset"),
Location: pulumi.String("us-central1"),
})
if err != nil {
return err
}
_, err = healthcare.NewFhirStore(ctx, "default", &healthcare.FhirStoreArgs{
Name: pulumi.String("example-fhir-store"),
Dataset: dataset.ID(),
Version: pulumi.String("R4"),
ComplexDataTypeReferenceParsing: pulumi.String("DISABLED"),
EnableUpdateCreate: pulumi.Bool(false),
DisableReferentialIntegrity: pulumi.Bool(false),
DisableResourceVersioning: pulumi.Bool(false),
EnableHistoryImport: pulumi.Bool(false),
DefaultSearchHandlingStrict: pulumi.Bool(false),
NotificationConfigs: healthcare.FhirStoreNotificationConfigArray{
&healthcare.FhirStoreNotificationConfigArgs{
PubsubTopic: topic.ID(),
},
},
Labels: pulumi.StringMap{
"label1": pulumi.String("labelvalue1"),
},
})
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 topic = new Gcp.PubSub.Topic("topic", new()
{
Name = "fhir-notifications",
});
var dataset = new Gcp.Healthcare.Dataset("dataset", new()
{
Name = "example-dataset",
Location = "us-central1",
});
var @default = new Gcp.Healthcare.FhirStore("default", new()
{
Name = "example-fhir-store",
Dataset = dataset.Id,
Version = "R4",
ComplexDataTypeReferenceParsing = "DISABLED",
EnableUpdateCreate = false,
DisableReferentialIntegrity = false,
DisableResourceVersioning = false,
EnableHistoryImport = false,
DefaultSearchHandlingStrict = false,
NotificationConfigs = new[]
{
new Gcp.Healthcare.Inputs.FhirStoreNotificationConfigArgs
{
PubsubTopic = topic.Id,
},
},
Labels =
{
{ "label1", "labelvalue1" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.pubsub.Topic;
import com.pulumi.gcp.pubsub.TopicArgs;
import com.pulumi.gcp.healthcare.Dataset;
import com.pulumi.gcp.healthcare.DatasetArgs;
import com.pulumi.gcp.healthcare.FhirStore;
import com.pulumi.gcp.healthcare.FhirStoreArgs;
import com.pulumi.gcp.healthcare.inputs.FhirStoreNotificationConfigArgs;
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 topic = new Topic("topic", TopicArgs.builder()
.name("fhir-notifications")
.build());
var dataset = new Dataset("dataset", DatasetArgs.builder()
.name("example-dataset")
.location("us-central1")
.build());
var default_ = new FhirStore("default", FhirStoreArgs.builder()
.name("example-fhir-store")
.dataset(dataset.id())
.version("R4")
.complexDataTypeReferenceParsing("DISABLED")
.enableUpdateCreate(false)
.disableReferentialIntegrity(false)
.disableResourceVersioning(false)
.enableHistoryImport(false)
.defaultSearchHandlingStrict(false)
.notificationConfigs(FhirStoreNotificationConfigArgs.builder()
.pubsubTopic(topic.id())
.build())
.labels(Map.of("label1", "labelvalue1"))
.build());
}
}
resources:
default:
type: gcp:healthcare:FhirStore
properties:
name: example-fhir-store
dataset: ${dataset.id}
version: R4
complexDataTypeReferenceParsing: DISABLED
enableUpdateCreate: false
disableReferentialIntegrity: false
disableResourceVersioning: false
enableHistoryImport: false
defaultSearchHandlingStrict: false
notificationConfigs:
- pubsubTopic: ${topic.id}
labels:
label1: labelvalue1
topic:
type: gcp:pubsub:Topic
properties:
name: fhir-notifications
dataset:
type: gcp:healthcare:Dataset
properties:
name: example-dataset
location: us-central1
The dataset property places the store within a Healthcare dataset. The version property selects the FHIR specification (DSTU2, STU3, or R4). The notificationConfigs array sends change events to Pub/Sub topics whenever resources are created, updated, or deleted. The complexDataTypeReferenceParsing property controls whether references within complex data types (like Extensions) are parsed for referential integrity checks.
Stream FHIR resources to BigQuery for analytics
Healthcare analytics pipelines often stream FHIR resources into BigQuery as they’re created or modified, enabling SQL-based analysis of patient data.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const dataset = new gcp.healthcare.Dataset("dataset", {
name: "example-dataset",
location: "us-central1",
});
const bqDataset = new gcp.bigquery.Dataset("bq_dataset", {
datasetId: "bq_example_dataset",
friendlyName: "test",
description: "This is a test description",
location: "US",
deleteContentsOnDestroy: true,
});
const _default = new gcp.healthcare.FhirStore("default", {
name: "example-fhir-store",
dataset: dataset.id,
version: "R4",
enableUpdateCreate: false,
disableReferentialIntegrity: false,
disableResourceVersioning: false,
enableHistoryImport: false,
labels: {
label1: "labelvalue1",
},
streamConfigs: [{
resourceTypes: ["Observation"],
bigqueryDestination: {
datasetUri: pulumi.interpolate`bq://${bqDataset.project}.${bqDataset.datasetId}`,
schemaConfig: {
recursiveStructureDepth: 3,
lastUpdatedPartitionConfig: {
type: "HOUR",
expirationMs: "1000000",
},
},
},
}],
});
const topic = new gcp.pubsub.Topic("topic", {name: "fhir-notifications"});
import pulumi
import pulumi_gcp as gcp
dataset = gcp.healthcare.Dataset("dataset",
name="example-dataset",
location="us-central1")
bq_dataset = gcp.bigquery.Dataset("bq_dataset",
dataset_id="bq_example_dataset",
friendly_name="test",
description="This is a test description",
location="US",
delete_contents_on_destroy=True)
default = gcp.healthcare.FhirStore("default",
name="example-fhir-store",
dataset=dataset.id,
version="R4",
enable_update_create=False,
disable_referential_integrity=False,
disable_resource_versioning=False,
enable_history_import=False,
labels={
"label1": "labelvalue1",
},
stream_configs=[{
"resource_types": ["Observation"],
"bigquery_destination": {
"dataset_uri": pulumi.Output.all(
project=bq_dataset.project,
dataset_id=bq_dataset.dataset_id
).apply(lambda resolved_outputs: f"bq://{resolved_outputs['project']}.{resolved_outputs['dataset_id']}")
,
"schema_config": {
"recursive_structure_depth": 3,
"last_updated_partition_config": {
"type": "HOUR",
"expiration_ms": "1000000",
},
},
},
}])
topic = gcp.pubsub.Topic("topic", name="fhir-notifications")
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/bigquery"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/healthcare"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/pubsub"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
dataset, err := healthcare.NewDataset(ctx, "dataset", &healthcare.DatasetArgs{
Name: pulumi.String("example-dataset"),
Location: pulumi.String("us-central1"),
})
if err != nil {
return err
}
bqDataset, err := bigquery.NewDataset(ctx, "bq_dataset", &bigquery.DatasetArgs{
DatasetId: pulumi.String("bq_example_dataset"),
FriendlyName: pulumi.String("test"),
Description: pulumi.String("This is a test description"),
Location: pulumi.String("US"),
DeleteContentsOnDestroy: pulumi.Bool(true),
})
if err != nil {
return err
}
_, err = healthcare.NewFhirStore(ctx, "default", &healthcare.FhirStoreArgs{
Name: pulumi.String("example-fhir-store"),
Dataset: dataset.ID(),
Version: pulumi.String("R4"),
EnableUpdateCreate: pulumi.Bool(false),
DisableReferentialIntegrity: pulumi.Bool(false),
DisableResourceVersioning: pulumi.Bool(false),
EnableHistoryImport: pulumi.Bool(false),
Labels: pulumi.StringMap{
"label1": pulumi.String("labelvalue1"),
},
StreamConfigs: healthcare.FhirStoreStreamConfigArray{
&healthcare.FhirStoreStreamConfigArgs{
ResourceTypes: pulumi.StringArray{
pulumi.String("Observation"),
},
BigqueryDestination: &healthcare.FhirStoreStreamConfigBigqueryDestinationArgs{
DatasetUri: pulumi.All(bqDataset.Project, bqDataset.DatasetId).ApplyT(func(_args []interface{}) (string, error) {
project := _args[0].(string)
datasetId := _args[1].(string)
return fmt.Sprintf("bq://%v.%v", project, datasetId), nil
}).(pulumi.StringOutput),
SchemaConfig: &healthcare.FhirStoreStreamConfigBigqueryDestinationSchemaConfigArgs{
RecursiveStructureDepth: pulumi.Int(3),
LastUpdatedPartitionConfig: &healthcare.FhirStoreStreamConfigBigqueryDestinationSchemaConfigLastUpdatedPartitionConfigArgs{
Type: pulumi.String("HOUR"),
ExpirationMs: pulumi.String("1000000"),
},
},
},
},
},
})
if err != nil {
return err
}
_, err = pubsub.NewTopic(ctx, "topic", &pubsub.TopicArgs{
Name: pulumi.String("fhir-notifications"),
})
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 dataset = new Gcp.Healthcare.Dataset("dataset", new()
{
Name = "example-dataset",
Location = "us-central1",
});
var bqDataset = new Gcp.BigQuery.Dataset("bq_dataset", new()
{
DatasetId = "bq_example_dataset",
FriendlyName = "test",
Description = "This is a test description",
Location = "US",
DeleteContentsOnDestroy = true,
});
var @default = new Gcp.Healthcare.FhirStore("default", new()
{
Name = "example-fhir-store",
Dataset = dataset.Id,
Version = "R4",
EnableUpdateCreate = false,
DisableReferentialIntegrity = false,
DisableResourceVersioning = false,
EnableHistoryImport = false,
Labels =
{
{ "label1", "labelvalue1" },
},
StreamConfigs = new[]
{
new Gcp.Healthcare.Inputs.FhirStoreStreamConfigArgs
{
ResourceTypes = new[]
{
"Observation",
},
BigqueryDestination = new Gcp.Healthcare.Inputs.FhirStoreStreamConfigBigqueryDestinationArgs
{
DatasetUri = Output.Tuple(bqDataset.Project, bqDataset.DatasetId).Apply(values =>
{
var project = values.Item1;
var datasetId = values.Item2;
return $"bq://{project}.{datasetId}";
}),
SchemaConfig = new Gcp.Healthcare.Inputs.FhirStoreStreamConfigBigqueryDestinationSchemaConfigArgs
{
RecursiveStructureDepth = 3,
LastUpdatedPartitionConfig = new Gcp.Healthcare.Inputs.FhirStoreStreamConfigBigqueryDestinationSchemaConfigLastUpdatedPartitionConfigArgs
{
Type = "HOUR",
ExpirationMs = "1000000",
},
},
},
},
},
});
var topic = new Gcp.PubSub.Topic("topic", new()
{
Name = "fhir-notifications",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.healthcare.FhirStore;
import com.pulumi.gcp.healthcare.FhirStoreArgs;
import com.pulumi.gcp.healthcare.inputs.FhirStoreStreamConfigArgs;
import com.pulumi.gcp.healthcare.inputs.FhirStoreStreamConfigBigqueryDestinationArgs;
import com.pulumi.gcp.healthcare.inputs.FhirStoreStreamConfigBigqueryDestinationSchemaConfigArgs;
import com.pulumi.gcp.healthcare.inputs.FhirStoreStreamConfigBigqueryDestinationSchemaConfigLastUpdatedPartitionConfigArgs;
import com.pulumi.gcp.pubsub.Topic;
import com.pulumi.gcp.pubsub.TopicArgs;
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 dataset = new com.pulumi.gcp.healthcare.Dataset("dataset", com.pulumi.gcp.healthcare.DatasetArgs.builder()
.name("example-dataset")
.location("us-central1")
.build());
var bqDataset = new com.pulumi.gcp.bigquery.Dataset("bqDataset", com.pulumi.gcp.bigquery.DatasetArgs.builder()
.datasetId("bq_example_dataset")
.friendlyName("test")
.description("This is a test description")
.location("US")
.deleteContentsOnDestroy(true)
.build());
var default_ = new FhirStore("default", FhirStoreArgs.builder()
.name("example-fhir-store")
.dataset(dataset.id())
.version("R4")
.enableUpdateCreate(false)
.disableReferentialIntegrity(false)
.disableResourceVersioning(false)
.enableHistoryImport(false)
.labels(Map.of("label1", "labelvalue1"))
.streamConfigs(FhirStoreStreamConfigArgs.builder()
.resourceTypes("Observation")
.bigqueryDestination(FhirStoreStreamConfigBigqueryDestinationArgs.builder()
.datasetUri(Output.tuple(bqDataset.project(), bqDataset.datasetId()).applyValue(values -> {
var project = values.t1;
var datasetId = values.t2;
return String.format("bq://%s.%s", project,datasetId);
}))
.schemaConfig(FhirStoreStreamConfigBigqueryDestinationSchemaConfigArgs.builder()
.recursiveStructureDepth(3)
.lastUpdatedPartitionConfig(FhirStoreStreamConfigBigqueryDestinationSchemaConfigLastUpdatedPartitionConfigArgs.builder()
.type("HOUR")
.expirationMs("1000000")
.build())
.build())
.build())
.build())
.build());
var topic = new Topic("topic", TopicArgs.builder()
.name("fhir-notifications")
.build());
}
}
resources:
default:
type: gcp:healthcare:FhirStore
properties:
name: example-fhir-store
dataset: ${dataset.id}
version: R4
enableUpdateCreate: false
disableReferentialIntegrity: false
disableResourceVersioning: false
enableHistoryImport: false
labels:
label1: labelvalue1
streamConfigs:
- resourceTypes:
- Observation
bigqueryDestination:
datasetUri: bq://${bqDataset.project}.${bqDataset.datasetId}
schemaConfig:
recursiveStructureDepth: 3
lastUpdatedPartitionConfig:
type: HOUR
expirationMs: 1e+06
topic:
type: gcp:pubsub:Topic
properties:
name: fhir-notifications
dataset:
type: gcp:healthcare:Dataset
properties:
name: example-dataset
location: us-central1
bqDataset:
type: gcp:bigquery:Dataset
name: bq_dataset
properties:
datasetId: bq_example_dataset
friendlyName: test
description: This is a test description
location: US
deleteContentsOnDestroy: true
The streamConfigs array defines streaming destinations. Each config specifies resourceTypes to stream (like Observation) and a bigqueryDestination with a datasetUri pointing to your BigQuery dataset. The schemaConfig controls how FHIR resources are flattened into BigQuery tables, including recursiveStructureDepth for nested fields and lastUpdatedPartitionConfig for time-based partitioning. Before adding streaming configs, you must grant the bigquery.dataEditor role to your project’s Cloud Healthcare Service Agent.
Configure detailed notification payloads
Some workflows need the full resource content in notifications rather than just change events, or need to track what was deleted.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const topic = new gcp.pubsub.Topic("topic", {name: "fhir-notifications"});
const dataset = new gcp.healthcare.Dataset("dataset", {
name: "example-dataset",
location: "us-central1",
});
const _default = new gcp.healthcare.FhirStore("default", {
name: "example-fhir-store",
dataset: dataset.id,
version: "R4",
enableUpdateCreate: false,
disableReferentialIntegrity: false,
disableResourceVersioning: false,
enableHistoryImport: false,
labels: {
label1: "labelvalue1",
},
notificationConfigs: [{
pubsubTopic: topic.id,
sendFullResource: true,
sendPreviousResourceOnDelete: true,
}],
});
import pulumi
import pulumi_gcp as gcp
topic = gcp.pubsub.Topic("topic", name="fhir-notifications")
dataset = gcp.healthcare.Dataset("dataset",
name="example-dataset",
location="us-central1")
default = gcp.healthcare.FhirStore("default",
name="example-fhir-store",
dataset=dataset.id,
version="R4",
enable_update_create=False,
disable_referential_integrity=False,
disable_resource_versioning=False,
enable_history_import=False,
labels={
"label1": "labelvalue1",
},
notification_configs=[{
"pubsub_topic": topic.id,
"send_full_resource": True,
"send_previous_resource_on_delete": True,
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/healthcare"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/pubsub"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
topic, err := pubsub.NewTopic(ctx, "topic", &pubsub.TopicArgs{
Name: pulumi.String("fhir-notifications"),
})
if err != nil {
return err
}
dataset, err := healthcare.NewDataset(ctx, "dataset", &healthcare.DatasetArgs{
Name: pulumi.String("example-dataset"),
Location: pulumi.String("us-central1"),
})
if err != nil {
return err
}
_, err = healthcare.NewFhirStore(ctx, "default", &healthcare.FhirStoreArgs{
Name: pulumi.String("example-fhir-store"),
Dataset: dataset.ID(),
Version: pulumi.String("R4"),
EnableUpdateCreate: pulumi.Bool(false),
DisableReferentialIntegrity: pulumi.Bool(false),
DisableResourceVersioning: pulumi.Bool(false),
EnableHistoryImport: pulumi.Bool(false),
Labels: pulumi.StringMap{
"label1": pulumi.String("labelvalue1"),
},
NotificationConfigs: healthcare.FhirStoreNotificationConfigArray{
&healthcare.FhirStoreNotificationConfigArgs{
PubsubTopic: topic.ID(),
SendFullResource: pulumi.Bool(true),
SendPreviousResourceOnDelete: 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 topic = new Gcp.PubSub.Topic("topic", new()
{
Name = "fhir-notifications",
});
var dataset = new Gcp.Healthcare.Dataset("dataset", new()
{
Name = "example-dataset",
Location = "us-central1",
});
var @default = new Gcp.Healthcare.FhirStore("default", new()
{
Name = "example-fhir-store",
Dataset = dataset.Id,
Version = "R4",
EnableUpdateCreate = false,
DisableReferentialIntegrity = false,
DisableResourceVersioning = false,
EnableHistoryImport = false,
Labels =
{
{ "label1", "labelvalue1" },
},
NotificationConfigs = new[]
{
new Gcp.Healthcare.Inputs.FhirStoreNotificationConfigArgs
{
PubsubTopic = topic.Id,
SendFullResource = true,
SendPreviousResourceOnDelete = true,
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.pubsub.Topic;
import com.pulumi.gcp.pubsub.TopicArgs;
import com.pulumi.gcp.healthcare.Dataset;
import com.pulumi.gcp.healthcare.DatasetArgs;
import com.pulumi.gcp.healthcare.FhirStore;
import com.pulumi.gcp.healthcare.FhirStoreArgs;
import com.pulumi.gcp.healthcare.inputs.FhirStoreNotificationConfigArgs;
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 topic = new Topic("topic", TopicArgs.builder()
.name("fhir-notifications")
.build());
var dataset = new Dataset("dataset", DatasetArgs.builder()
.name("example-dataset")
.location("us-central1")
.build());
var default_ = new FhirStore("default", FhirStoreArgs.builder()
.name("example-fhir-store")
.dataset(dataset.id())
.version("R4")
.enableUpdateCreate(false)
.disableReferentialIntegrity(false)
.disableResourceVersioning(false)
.enableHistoryImport(false)
.labels(Map.of("label1", "labelvalue1"))
.notificationConfigs(FhirStoreNotificationConfigArgs.builder()
.pubsubTopic(topic.id())
.sendFullResource(true)
.sendPreviousResourceOnDelete(true)
.build())
.build());
}
}
resources:
default:
type: gcp:healthcare:FhirStore
properties:
name: example-fhir-store
dataset: ${dataset.id}
version: R4
enableUpdateCreate: false
disableReferentialIntegrity: false
disableResourceVersioning: false
enableHistoryImport: false
labels:
label1: labelvalue1
notificationConfigs:
- pubsubTopic: ${topic.id}
sendFullResource: true
sendPreviousResourceOnDelete: true
topic:
type: gcp:pubsub:Topic
properties:
name: fhir-notifications
dataset:
type: gcp:healthcare:Dataset
properties:
name: example-dataset
location: us-central1
The sendFullResource property includes the complete FHIR resource in each notification message, not just metadata about the change. The sendPreviousResourceOnDelete property sends the deleted resource’s content when resources are removed, enabling audit trails and recovery workflows.
Enforce consent-based access controls
Healthcare applications subject to privacy regulations often need to enforce patient consent before allowing access to FHIR resources.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const topic = new gcp.pubsub.Topic("topic", {name: "fhir-notifications"});
const dataset = new gcp.healthcare.Dataset("dataset", {
name: "example-dataset",
location: "us-central1",
});
const _default = new gcp.healthcare.FhirStore("default", {
name: "example-fhir-store",
dataset: dataset.id,
version: "R4",
complexDataTypeReferenceParsing: "DISABLED",
enableUpdateCreate: false,
disableReferentialIntegrity: false,
disableResourceVersioning: false,
enableHistoryImport: false,
defaultSearchHandlingStrict: false,
notificationConfigs: [{
pubsubTopic: topic.id,
}],
labels: {
label1: "labelvalue1",
},
consentConfig: {
version: "V1",
accessEnforced: true,
consentHeaderHandling: {
profile: "REQUIRED_ON_READ",
},
accessDeterminationLogConfig: {
logLevel: "VERBOSE",
},
},
});
import pulumi
import pulumi_gcp as gcp
topic = gcp.pubsub.Topic("topic", name="fhir-notifications")
dataset = gcp.healthcare.Dataset("dataset",
name="example-dataset",
location="us-central1")
default = gcp.healthcare.FhirStore("default",
name="example-fhir-store",
dataset=dataset.id,
version="R4",
complex_data_type_reference_parsing="DISABLED",
enable_update_create=False,
disable_referential_integrity=False,
disable_resource_versioning=False,
enable_history_import=False,
default_search_handling_strict=False,
notification_configs=[{
"pubsub_topic": topic.id,
}],
labels={
"label1": "labelvalue1",
},
consent_config={
"version": "V1",
"access_enforced": True,
"consent_header_handling": {
"profile": "REQUIRED_ON_READ",
},
"access_determination_log_config": {
"log_level": "VERBOSE",
},
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/healthcare"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/pubsub"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
topic, err := pubsub.NewTopic(ctx, "topic", &pubsub.TopicArgs{
Name: pulumi.String("fhir-notifications"),
})
if err != nil {
return err
}
dataset, err := healthcare.NewDataset(ctx, "dataset", &healthcare.DatasetArgs{
Name: pulumi.String("example-dataset"),
Location: pulumi.String("us-central1"),
})
if err != nil {
return err
}
_, err = healthcare.NewFhirStore(ctx, "default", &healthcare.FhirStoreArgs{
Name: pulumi.String("example-fhir-store"),
Dataset: dataset.ID(),
Version: pulumi.String("R4"),
ComplexDataTypeReferenceParsing: pulumi.String("DISABLED"),
EnableUpdateCreate: pulumi.Bool(false),
DisableReferentialIntegrity: pulumi.Bool(false),
DisableResourceVersioning: pulumi.Bool(false),
EnableHistoryImport: pulumi.Bool(false),
DefaultSearchHandlingStrict: pulumi.Bool(false),
NotificationConfigs: healthcare.FhirStoreNotificationConfigArray{
&healthcare.FhirStoreNotificationConfigArgs{
PubsubTopic: topic.ID(),
},
},
Labels: pulumi.StringMap{
"label1": pulumi.String("labelvalue1"),
},
ConsentConfig: &healthcare.FhirStoreConsentConfigArgs{
Version: pulumi.String("V1"),
AccessEnforced: pulumi.Bool(true),
ConsentHeaderHandling: &healthcare.FhirStoreConsentConfigConsentHeaderHandlingArgs{
Profile: pulumi.String("REQUIRED_ON_READ"),
},
AccessDeterminationLogConfig: &healthcare.FhirStoreConsentConfigAccessDeterminationLogConfigArgs{
LogLevel: pulumi.String("VERBOSE"),
},
},
})
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 topic = new Gcp.PubSub.Topic("topic", new()
{
Name = "fhir-notifications",
});
var dataset = new Gcp.Healthcare.Dataset("dataset", new()
{
Name = "example-dataset",
Location = "us-central1",
});
var @default = new Gcp.Healthcare.FhirStore("default", new()
{
Name = "example-fhir-store",
Dataset = dataset.Id,
Version = "R4",
ComplexDataTypeReferenceParsing = "DISABLED",
EnableUpdateCreate = false,
DisableReferentialIntegrity = false,
DisableResourceVersioning = false,
EnableHistoryImport = false,
DefaultSearchHandlingStrict = false,
NotificationConfigs = new[]
{
new Gcp.Healthcare.Inputs.FhirStoreNotificationConfigArgs
{
PubsubTopic = topic.Id,
},
},
Labels =
{
{ "label1", "labelvalue1" },
},
ConsentConfig = new Gcp.Healthcare.Inputs.FhirStoreConsentConfigArgs
{
Version = "V1",
AccessEnforced = true,
ConsentHeaderHandling = new Gcp.Healthcare.Inputs.FhirStoreConsentConfigConsentHeaderHandlingArgs
{
Profile = "REQUIRED_ON_READ",
},
AccessDeterminationLogConfig = new Gcp.Healthcare.Inputs.FhirStoreConsentConfigAccessDeterminationLogConfigArgs
{
LogLevel = "VERBOSE",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.pubsub.Topic;
import com.pulumi.gcp.pubsub.TopicArgs;
import com.pulumi.gcp.healthcare.Dataset;
import com.pulumi.gcp.healthcare.DatasetArgs;
import com.pulumi.gcp.healthcare.FhirStore;
import com.pulumi.gcp.healthcare.FhirStoreArgs;
import com.pulumi.gcp.healthcare.inputs.FhirStoreNotificationConfigArgs;
import com.pulumi.gcp.healthcare.inputs.FhirStoreConsentConfigArgs;
import com.pulumi.gcp.healthcare.inputs.FhirStoreConsentConfigConsentHeaderHandlingArgs;
import com.pulumi.gcp.healthcare.inputs.FhirStoreConsentConfigAccessDeterminationLogConfigArgs;
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 topic = new Topic("topic", TopicArgs.builder()
.name("fhir-notifications")
.build());
var dataset = new Dataset("dataset", DatasetArgs.builder()
.name("example-dataset")
.location("us-central1")
.build());
var default_ = new FhirStore("default", FhirStoreArgs.builder()
.name("example-fhir-store")
.dataset(dataset.id())
.version("R4")
.complexDataTypeReferenceParsing("DISABLED")
.enableUpdateCreate(false)
.disableReferentialIntegrity(false)
.disableResourceVersioning(false)
.enableHistoryImport(false)
.defaultSearchHandlingStrict(false)
.notificationConfigs(FhirStoreNotificationConfigArgs.builder()
.pubsubTopic(topic.id())
.build())
.labels(Map.of("label1", "labelvalue1"))
.consentConfig(FhirStoreConsentConfigArgs.builder()
.version("V1")
.accessEnforced(true)
.consentHeaderHandling(FhirStoreConsentConfigConsentHeaderHandlingArgs.builder()
.profile("REQUIRED_ON_READ")
.build())
.accessDeterminationLogConfig(FhirStoreConsentConfigAccessDeterminationLogConfigArgs.builder()
.logLevel("VERBOSE")
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:healthcare:FhirStore
properties:
name: example-fhir-store
dataset: ${dataset.id}
version: R4
complexDataTypeReferenceParsing: DISABLED
enableUpdateCreate: false
disableReferentialIntegrity: false
disableResourceVersioning: false
enableHistoryImport: false
defaultSearchHandlingStrict: false
notificationConfigs:
- pubsubTopic: ${topic.id}
labels:
label1: labelvalue1
consentConfig:
version: V1
accessEnforced: true
consentHeaderHandling:
profile: REQUIRED_ON_READ
accessDeterminationLogConfig:
logLevel: VERBOSE
topic:
type: gcp:pubsub:Topic
properties:
name: fhir-notifications
dataset:
type: gcp:healthcare:Dataset
properties:
name: example-dataset
location: us-central1
The consentConfig block enables consent enforcement. The accessEnforced property requires consent verification for all access requests. The consentHeaderHandling property controls how consent headers are processed (REQUIRED_ON_READ means clients must provide consent information). The accessDeterminationLogConfig property logs consent decisions at VERBOSE level for audit purposes. Consent enforcement is not available for DSTU2 FHIR version due to absence of Consent resources.
Disable FHIR validation for flexible ingestion
During migrations or when ingesting data from legacy systems, strict FHIR validation can block otherwise usable resources.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const topic = new gcp.pubsub.Topic("topic", {name: "fhir-notifications"});
const dataset = new gcp.healthcare.Dataset("dataset", {
name: "example-dataset",
location: "us-central1",
});
const _default = new gcp.healthcare.FhirStore("default", {
name: "example-fhir-store",
dataset: dataset.id,
version: "R4",
complexDataTypeReferenceParsing: "DISABLED",
enableUpdateCreate: false,
disableReferentialIntegrity: false,
disableResourceVersioning: false,
enableHistoryImport: false,
defaultSearchHandlingStrict: false,
notificationConfigs: [{
pubsubTopic: topic.id,
}],
labels: {
label1: "labelvalue1",
},
validationConfig: {
disableProfileValidation: true,
enabledImplementationGuides: [],
disableRequiredFieldValidation: true,
disableReferenceTypeValidation: true,
disableFhirpathValidation: true,
},
});
import pulumi
import pulumi_gcp as gcp
topic = gcp.pubsub.Topic("topic", name="fhir-notifications")
dataset = gcp.healthcare.Dataset("dataset",
name="example-dataset",
location="us-central1")
default = gcp.healthcare.FhirStore("default",
name="example-fhir-store",
dataset=dataset.id,
version="R4",
complex_data_type_reference_parsing="DISABLED",
enable_update_create=False,
disable_referential_integrity=False,
disable_resource_versioning=False,
enable_history_import=False,
default_search_handling_strict=False,
notification_configs=[{
"pubsub_topic": topic.id,
}],
labels={
"label1": "labelvalue1",
},
validation_config={
"disable_profile_validation": True,
"enabled_implementation_guides": [],
"disable_required_field_validation": True,
"disable_reference_type_validation": True,
"disable_fhirpath_validation": True,
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/healthcare"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/pubsub"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
topic, err := pubsub.NewTopic(ctx, "topic", &pubsub.TopicArgs{
Name: pulumi.String("fhir-notifications"),
})
if err != nil {
return err
}
dataset, err := healthcare.NewDataset(ctx, "dataset", &healthcare.DatasetArgs{
Name: pulumi.String("example-dataset"),
Location: pulumi.String("us-central1"),
})
if err != nil {
return err
}
_, err = healthcare.NewFhirStore(ctx, "default", &healthcare.FhirStoreArgs{
Name: pulumi.String("example-fhir-store"),
Dataset: dataset.ID(),
Version: pulumi.String("R4"),
ComplexDataTypeReferenceParsing: pulumi.String("DISABLED"),
EnableUpdateCreate: pulumi.Bool(false),
DisableReferentialIntegrity: pulumi.Bool(false),
DisableResourceVersioning: pulumi.Bool(false),
EnableHistoryImport: pulumi.Bool(false),
DefaultSearchHandlingStrict: pulumi.Bool(false),
NotificationConfigs: healthcare.FhirStoreNotificationConfigArray{
&healthcare.FhirStoreNotificationConfigArgs{
PubsubTopic: topic.ID(),
},
},
Labels: pulumi.StringMap{
"label1": pulumi.String("labelvalue1"),
},
ValidationConfig: &healthcare.FhirStoreValidationConfigArgs{
DisableProfileValidation: pulumi.Bool(true),
EnabledImplementationGuides: pulumi.StringArray{},
DisableRequiredFieldValidation: pulumi.Bool(true),
DisableReferenceTypeValidation: pulumi.Bool(true),
DisableFhirpathValidation: 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 topic = new Gcp.PubSub.Topic("topic", new()
{
Name = "fhir-notifications",
});
var dataset = new Gcp.Healthcare.Dataset("dataset", new()
{
Name = "example-dataset",
Location = "us-central1",
});
var @default = new Gcp.Healthcare.FhirStore("default", new()
{
Name = "example-fhir-store",
Dataset = dataset.Id,
Version = "R4",
ComplexDataTypeReferenceParsing = "DISABLED",
EnableUpdateCreate = false,
DisableReferentialIntegrity = false,
DisableResourceVersioning = false,
EnableHistoryImport = false,
DefaultSearchHandlingStrict = false,
NotificationConfigs = new[]
{
new Gcp.Healthcare.Inputs.FhirStoreNotificationConfigArgs
{
PubsubTopic = topic.Id,
},
},
Labels =
{
{ "label1", "labelvalue1" },
},
ValidationConfig = new Gcp.Healthcare.Inputs.FhirStoreValidationConfigArgs
{
DisableProfileValidation = true,
EnabledImplementationGuides = new() { },
DisableRequiredFieldValidation = true,
DisableReferenceTypeValidation = true,
DisableFhirpathValidation = true,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.pubsub.Topic;
import com.pulumi.gcp.pubsub.TopicArgs;
import com.pulumi.gcp.healthcare.Dataset;
import com.pulumi.gcp.healthcare.DatasetArgs;
import com.pulumi.gcp.healthcare.FhirStore;
import com.pulumi.gcp.healthcare.FhirStoreArgs;
import com.pulumi.gcp.healthcare.inputs.FhirStoreNotificationConfigArgs;
import com.pulumi.gcp.healthcare.inputs.FhirStoreValidationConfigArgs;
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 topic = new Topic("topic", TopicArgs.builder()
.name("fhir-notifications")
.build());
var dataset = new Dataset("dataset", DatasetArgs.builder()
.name("example-dataset")
.location("us-central1")
.build());
var default_ = new FhirStore("default", FhirStoreArgs.builder()
.name("example-fhir-store")
.dataset(dataset.id())
.version("R4")
.complexDataTypeReferenceParsing("DISABLED")
.enableUpdateCreate(false)
.disableReferentialIntegrity(false)
.disableResourceVersioning(false)
.enableHistoryImport(false)
.defaultSearchHandlingStrict(false)
.notificationConfigs(FhirStoreNotificationConfigArgs.builder()
.pubsubTopic(topic.id())
.build())
.labels(Map.of("label1", "labelvalue1"))
.validationConfig(FhirStoreValidationConfigArgs.builder()
.disableProfileValidation(true)
.enabledImplementationGuides()
.disableRequiredFieldValidation(true)
.disableReferenceTypeValidation(true)
.disableFhirpathValidation(true)
.build())
.build());
}
}
resources:
default:
type: gcp:healthcare:FhirStore
properties:
name: example-fhir-store
dataset: ${dataset.id}
version: R4
complexDataTypeReferenceParsing: DISABLED
enableUpdateCreate: false
disableReferentialIntegrity: false
disableResourceVersioning: false
enableHistoryImport: false
defaultSearchHandlingStrict: false
notificationConfigs:
- pubsubTopic: ${topic.id}
labels:
label1: labelvalue1
validationConfig:
disableProfileValidation: true
enabledImplementationGuides: []
disableRequiredFieldValidation: true
disableReferenceTypeValidation: true
disableFhirpathValidation: true
topic:
type: gcp:pubsub:Topic
properties:
name: fhir-notifications
dataset:
type: gcp:healthcare:Dataset
properties:
name: example-dataset
location: us-central1
The validationConfig block controls FHIR validation behavior. Setting disableProfileValidation, disableRequiredFieldValidation, disableReferenceTypeValidation, and disableFhirpathValidation to true allows non-conformant resources to be stored. This is useful during data migrations when source systems produce FHIR resources that don’t fully conform to specification requirements.
Beyond these examples
These snippets focus on specific FHIR store features: Pub/Sub notifications and BigQuery streaming, consent enforcement and validation controls, and FHIR version selection and reference parsing. They’re intentionally minimal rather than full healthcare data platforms.
The examples reference pre-existing infrastructure such as Healthcare datasets, Pub/Sub topics for notifications, and BigQuery datasets for streaming destinations. They focus on configuring the FHIR store rather than provisioning the surrounding infrastructure.
To keep things focused, common FHIR store patterns are omitted, including:
- Referential integrity controls (disableReferentialIntegrity)
- Resource versioning behavior (disableResourceVersioning)
- History import capabilities (enableHistoryImport)
- Client-specified IDs (enableUpdateCreate)
- Search parameter handling (defaultSearchHandlingStrict)
These omissions are intentional: the goal is to illustrate how each FHIR store feature is wired, not provide drop-in healthcare data modules. See the FHIR Store resource reference for all available configuration options.
Let's create GCP Healthcare FHIR Stores
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Data Loss & Immutability
name, disableReferentialIntegrity, disableResourceVersioning, or enableHistoryImport recreates the store and removes all data. Plan these settings carefully during initial creation.enableHistoryImport can be changed manually in the Google Cloud Healthcare admin console without recreating the FHIR store, even though Pulumi treats it as immutable.FHIR Versioning & Compatibility
version property is immutable after creation.consentConfig is not available for DSTU2 (due to absence of Consent resources) and not supported for R5.Streaming & BigQuery Integration
bigquery.dataEditor role to your project’s Cloud Healthcare Service Agent service account before configuring streamConfigs.streamConfigs.Notifications & Pub/Sub
notificationConfigs. The notificationConfig property is deprecated and will be removed in a future major release.sendFullResource to true in your notificationConfigs. You can also enable sendPreviousResourceOnDelete to include the resource state before deletion.Security & Compliance
disableReferentialIntegrity is true, the API skips referential integrity checks. Operations like Patient.get$everything may not return all results if broken references exist.Labels & Metadata
[\p{Ll}\p{Lo}][\p{Ll}\p{Lo}\p{N}_-]{0,62}. Values must be 1-63 characters matching [\p{Ll}\p{Lo}\p{N}_-]{0,63}. Maximum 64 labels per store. The labels field is non-authoritative; use effectiveLabels to see all labels.