The gcp:healthcare/fhirStore:FhirStore resource, part of the Pulumi GCP provider, defines a FHIR store within a Healthcare dataset: its FHIR version, data integrity rules, and export destinations. This guide focuses on three capabilities: FHIR version and integrity configuration, BigQuery streaming and Pub/Sub notifications, and consent enforcement and validation controls.
FHIR stores belong to Healthcare datasets and 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 deployments start by creating a store within a Healthcare dataset, choosing a FHIR version, and configuring integrity behavior. Pub/Sub notifications let downstream systems react to resource 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 complexDataTypeReferenceParsing property controls whether references inside complex data types like Extensions are parsed for integrity checks. The disableReferentialIntegrity and disableResourceVersioning properties are immutable after creation; changing them recreates the store and removes all data. The notificationConfigs array sends change events to Pub/Sub topics.
Stream FHIR resources to BigQuery for analytics
Healthcare analytics pipelines often need FHIR data in BigQuery for SQL-based analysis. Streaming configs automatically export resource mutations as they occur.
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 export 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: recursiveStructureDepth sets nesting depth, and lastUpdatedPartitionConfig creates time-based partitions. Before adding streaming configs, grant the bigquery.dataEditor role to your project’s Cloud Healthcare Service Agent.
Configure detailed Pub/Sub notifications with full resources
Some notification consumers need complete resource payloads rather than just change events.
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 entire FHIR resource in notifications, not just metadata. The sendPreviousResourceOnDelete property sends the resource state before deletion, allowing consumers to track what was removed. This extends the basic notification setup with additional payload options.
Enforce consent-based access controls
Healthcare applications subject to privacy regulations often need to enforce patient consent before allowing resource access.
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 evaluation for all access requests. The consentHeaderHandling property controls how consent headers are processed; setting profile to REQUIRED_ON_READ means clients must provide consent information in read requests. The accessDeterminationLogConfig property logs consent decisions at the specified verbosity level. Consent enforcement is not available for DSTU2 (no Consent resources) or R5 FHIR versions.
Disable FHIR validation for flexible data ingestion
During data migration or when working with non-standard FHIR implementations, strict validation can block legitimate data.
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 rules. Setting disableProfileValidation, disableRequiredFieldValidation, disableReferenceTypeValidation, and disableFhirpathValidation to true relaxes validation, allowing ingestion of resources that don’t strictly conform to FHIR profiles. This is useful for migration scenarios where source data may not meet all FHIR requirements.
Beyond these examples
These snippets focus on specific FHIR store features: FHIR version selection and integrity controls, BigQuery streaming and Pub/Sub notifications, and consent enforcement and validation configuration. 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 exports. They focus on configuring the FHIR store rather than provisioning the surrounding infrastructure.
To keep things focused, common FHIR store patterns are omitted, including:
- History import and modification controls (enableHistoryImport, enableHistoryModifications)
- Search behavior configuration (defaultSearchHandlingStrict)
- Client-specified resource IDs (enableUpdateCreate)
- Labels and metadata organization
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 FHIR store and deletes all data. The dataset and version properties are also immutable. Plan these settings carefully during initial creation.enableHistoryImport can be changed manually in the Google Cloud Healthcare admin console without triggering store recreation, even though it’s marked as immutable in Pulumi.complexDataTypeReferenceParsing to ENABLED causes processing to fail if existing resources contain references to non-existent resources. Ensure all references are valid before enabling this feature.Configuration & Setup
streamConfigs, grant the bigquery.dataEditor role to your project’s Cloud Healthcare Service Agent service account. Streaming results typically appear after a lag of dozens of seconds.labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels to see all labels present on the resource, including those set by other clients.FHIR Version Compatibility
DSTU2, STU3 (default), and R4. Consent enforcement (consentConfig) isn’t available for DSTU2 due to absence of Consent resources, and isn’t supported for R5.Notifications & Streaming
notificationConfigs (plural). The singular notificationConfig is deprecated and will be removed in a future major release.Security & Search Behavior
defaultSearchHandlingStrict to true returns errors for unrecognized search parameters (strict mode). Setting it to false ignores unrecognized parameters (lenient mode, FHIR specification default). You can override this per-request using the HTTP header Prefer: handling=strict or Prefer: handling=lenient.enableUpdateCreate is true, client-specified IDs may contain sensitive data like patient identifiers. These IDs appear in FHIR resource paths recorded in Cloud audit logs and Pub/Sub notifications, so treat audit logs with appropriate care.