Real-Time NoSQL Pipelines

Quote

In distributed data systems, at-least-once delivery is normal, so the platform has to make reprocessing safe.

Source: Data Engineering Design Patterns.pdf

Archived demo boundary

The original Firestore project used throughout this note, bq-wh-nb, has been removed. Treat all embedded Firestore or Eventarc outputs as archived reference material, not as live validation.

This refresh intentionally avoids rerunning cloud commands. The note keeps the former examples as operator patterns and adds only knowledge-backed corrections where current documentation changes the operational guidance.

Mental Model / Architecture Model

Firestore belongs in the hot operational path. Pub/Sub and Dataflow carry or transform events. BigQuery holds analytical history. Eventarc reacts to document mutations when the state store itself becomes the trigger.


flowchart LR
    A["Composer / Cloud Run jobs"] --> B["Firestore<br/>config, checkpoints, run state"]
    C["Producers"] --> D["Pub/Sub"]
    D --> E["Dataflow"]
    E --> B
    E --> F["BigQuery<br/>history and analytics"]
    B --> G["Eventarc"]
    G --> H["Cloud Run service<br/>lightweight reactions"]

The intent is deliberate:

  • Firestore holds current truth.
  • Pub/Sub holds transport pressure.
  • Dataflow handles throughput and transformation.
  • BigQuery holds analysis and long retention.
  • Eventarc reacts to state changes without polling.

Core Concepts

These concepts explain when Firestore earns a place in a real pipeline and when it should step aside.

Firestore | pipeline role | what Firestore should own

Firestore is strongest when it stores the current operational answer to a narrow question.

Pipeline responsibilityFirestore fitWhy
Current pipeline run stateStrong fitOne document can represent one run, one task, or one entity’s latest state
Pipeline checkpoint or watermarkStrong fitSmall writes, frequent reads, simple recovery logic
Config registry or feature flagsStrong fitOperators update one document and services reread it cheaply
Idempotency registerStrong fit for bounded windowsSmall keyed documents with TTL are straightforward
Full event logWeak fitEvent history belongs in Pub/Sub, Cloud Storage, or BigQuery
Warehouse-style history analyticsWeak fitFirestore read pricing and query model are the wrong fit

The recurring rule is that Firestore should own state, not transport and not large-scale history.

Firestore | integration patterns | picking the right companion service

The service pair matters more than whether Firestore is present at all.

PatternUse it whenFirestore responsibilityCompanion responsibility
Firestore + Eventarc + Cloud RunA document change should trigger lightweight downstream workHolds the current state that emits the eventEventarc routes; Cloud Run performs the reaction
Firestore + Pub/SubProducers and consumers must be decoupled and transport needs buffering or replayHolds current config, dedup state, or job statusPub/Sub carries messages and fan-out
Firestore + Pub/Sub + DataflowThroughput is too high for Firestore to be the transport layer and you need windowing or dual writesHolds serving summaries, checkpoints, or control-plane stateDataflow transforms and writes hot and cold outputs
Firestore + BigQueryYou need fast current state plus cheap analytical historyHolds hot operational truthBigQuery stores detailed or long-term history
Firestore + Composer / AirflowOrchestration needs globally visible job state, config, or backfill markersHolds orchestration metadata and run coordinationComposer schedules and executes the workflows

Firestore | delivery semantics | duplicates, ordering, and replay

Real-time and event-driven systems fail when teams pretend delivery is cleaner than it really is.

ConcernFirestore aloneBetter boundary
Exactly-once processingNot guaranteedMake writes idempotent and store dedup keys
Ordered event historyWeakUse Pub/Sub or a stream transport with retention semantics
Broad replayWeakUse Pub/Sub retention, exports, backups, or PITR
Low-latency current stateStrongKeep one current document per entity or workflow

Operationally, this means:

  • Assume Eventarc and retrying services can cause duplicate deliveries.
  • Use a stable idempotency key and write-side checks that are safe to repeat.
  • Keep replay manifests and checkpoints explicit.
  • Treat Firestore as the record of current progress, not the replay source of truth.

Firestore | cost and scaling | keeping the hot path cheap

Firestore’s cost model rewards narrow reads and bounded history. It punishes broad scans and unnecessary index fanout.

Cost or scaling driverPipeline mistakeBetter pattern
Document reads billed per documentScanning a whole run-history collection for dashboardsWrite one summary document per pipeline and read that
Index fanoutIndexing every timestamp and large array in a high-write collectionExempt non-query fields and keep document shapes compact
HotspottingSequential document IDs or lexicographically narrow writesScatter IDs and shard high-rate counters or state
Listener misuseLong-lived backend listeners where an event transport would be clearerUse Eventarc or Pub/Sub for server-side event flow

Operational Commands And Workflows

The commands below focus on platform readiness and integration boundaries, not SDK code. The original walkthrough used the removed project bq-wh-nb and the named Firestore database main, so captured outputs are archived examples and the commands should now be read as operator patterns.

PowerShell / Linux | gcloud | verify live pipeline prerequisites

Event-driven Firestore patterns fail most often because required services were never enabled or the trigger location does not match the database location.

List enabled APIs relevant to Firestore-driven pipelines

Before designing or deploying Firestore-triggered or Firestore-fed pipeline components. It is typically triggered by you need to know whether the project can currently support Eventarc, Cloud Run, Pub/Sub, Dataflow, and BigQuery integration patterns. gcloud CLI, read-only. Surface the service APIs that are already enabled so you can distinguish platform readiness from application errors.

FieldSource columnTypeMeaning
namename.basename()stringEnabled service API relevant to the pipeline pattern

List the enabled service APIs that matter most for Firestore-driven pipelines in the active project.

gcloud services list --enabled \
  --filter="name:(firestore.googleapis.com OR eventarc.googleapis.com OR run.googleapis.com OR pubsub.googleapis.com OR dataflow.googleapis.com OR bigquery.googleapis.com)" \
  --format="table(name.basename())"
NAME
bigquery.googleapis.com
firestore.googleapis.com
pubsub.googleapis.com

In the archived environment, this output showed that Firestore, Pub/Sub, and BigQuery patterns were ready, while Eventarc, Cloud Run, and Dataflow still needed project-level enablement.

Confirm the Firestore database location before creating triggers

Before creating Eventarc triggers, Cloud Run services, or cross-service wiring that depends on regional placement. It is typically triggered by you are about to create an Eventarc trigger or reason about latency between Firestore and compute. gcloud CLI, read-only. Confirm the Firestore database location so downstream services can be co-located correctly.

Print the location of the archived main Firestore database used in this note.

gcloud firestore databases describe \
  --database='main' \
  --format="value(locationId)"
europe-west1

For Firestore direct events, the trigger location and destination region should be chosen with this database location in mind.

Enable the missing APIs for Eventarc and Dataflow patterns

After verifying the project is missing Eventarc, Cloud Run, or Dataflow and before attempting to create triggers or launch streaming jobs. It is typically triggered by the service list shows the platform is not provisioned for the desired integration pattern. gcloud CLI, state-changing. Requires permission to enable services in the project. Provision the project-level APIs needed for Eventarc-triggered reactions and Dataflow-based processing.

Firestore direct-event prerequisites

For Firestore direct events, the Eventarc path requires more than just eventarc.googleapis.com and run.googleapis.com. Current Google Cloud documentation also calls out firestore.googleapis.com, eventarcpublishing.googleapis.com, and logging.googleapis.com as prerequisites for a Cloud Run trigger flow.

Keep that distinction explicit: Firestore direct events, Eventarc routing, and Dataflow processing are separate platform surfaces, so the enablement set should match the architecture you are actually deploying.

API enablement is a project-wide mutation

Before running this command, verify:

  • The active project is correct.
  • You intend to support Eventarc, Cloud Run, and Dataflow in this project.
  • Billing and IAM are already aligned for those services.

Enable only what the pattern actually needs

If the pattern is just Firestore plus BigQuery export, you may not need Eventarc or Dataflow at all. Keep the project surface area intentional.

Enable the APIs needed for Firestore-triggered Cloud Run workflows and Dataflow processing.

gcloud services enable \
  firestore.googleapis.com \
  eventarc.googleapis.com \
  eventarcpublishing.googleapis.com \
  logging.googleapis.com \
  run.googleapis.com \
  dataflow.googleapis.com

After running the command, repeat the enabled-services inspection and confirm the missing APIs now appear.

FlagSyntaxDescription
--enabledgcloud services list --enabledRestricts service listing to enabled APIs
--filter--filter="name:(...)"Narrows output to the APIs relevant to the pipeline pattern
--format--format="table(name.basename())"Produces readable, script-safe output
--database--database='main'Targets the named Firestore database

PowerShell / Linux | gcloud | create and inspect Eventarc-triggered Firestore workflows

Use this pattern when a document write itself is the event boundary and the downstream work is lightweight enough that Firestore should remain the control-plane source of truth.

Create a Firestore document-written trigger for Cloud Run

After enabling Eventarc and Cloud Run and after the destination service already exists. It is typically triggered by A write to a specific Firestore path such as pipeline_runs/{runId} should start a serverless reaction. gcloud CLI, state-changing. Requires Eventarc admin permissions and a service account that can invoke the destination service. Route Firestore document mutations into a Cloud Run service without a polling loop.

Location and identity must line up

Before running the trigger creation command, verify:

  • The Firestore database location is europe-west1.
  • The Cloud Run service exists in europe-west1.
  • The service account has permission to invoke the Cloud Run service.
  • The Firestore document path pattern matches only the documents you intend to react to.

Keep Eventarc handlers idempotent

Direct document events are not a guarantee of exactly-once processing. The Cloud Run handler should be able to repeat the same work safely when retries occur.

Create a trigger that routes writes to pipeline_runs/{runId} in database main into a Cloud Run service named pipeline-run-handler.

gcloud eventarc triggers create firestore-pipeline-runs-written \
  --location='europe-west1' \
  --destination-run-service='pipeline-run-handler' \
  --destination-run-region='europe-west1' \
  --event-filters="type=google.cloud.firestore.document.v1.written" \
  --event-filters="database=main" \
  --event-filters-path-pattern="document=pipeline_runs/{runId}" \
  --event-data-content-type='application/protobuf' \
  --service-account='eventarc-firestore@bq-wh-nb.iam.gserviceaccount.com'

After creating the trigger, use gcloud eventarc triggers list --location='europe-west1' to confirm it exists and gcloud eventarc triggers describe firestore-pipeline-runs-written --location='europe-west1' to inspect the bound filters.

Track long-running Firestore admin operations safely

During exports, imports, restores, or bulk deletes that have been started asynchronously. It is typically triggered by you need to verify progress or keep the operation name for later review. gcloud CLI. The initiating command returns or logs the operation name. Keep long-running admin work observable without assuming the default database ID is correct.

Do not rely on the default database

The original demo project used the named database main, not '(default)'. Current Cloud SDK releases expose --database on both gcloud firestore operations list and gcloud firestore operations describe, so the operational rule is to pass the named database explicitly instead of hoping the default matches reality.

Keep the operation name with the incident or change record

When you run an asynchronous Firestore admin command, persist the returned operation name in your ticket, runbook, or deployment log so it can be checked later without rediscovery.

Describe one Firestore admin operation by operation name returned from the initiating command.

gcloud firestore operations describe OPERATION_NAME \
  --database='main'
FlagSyntaxDescription
--location--location='europe-west1'Chooses the Eventarc trigger location
--destination-run-service--destination-run-service='pipeline-run-handler'Names the Cloud Run service to invoke
--destination-run-region--destination-run-region='europe-west1'Chooses the Cloud Run region
--event-filters--event-filters="database=main"Adds exact-match event attributes such as event type or database
--event-filters-path-pattern--event-filters-path-pattern="document=pipeline_runs/{runId}"Binds the trigger to a document path pattern
--event-data-content-type--event-data-content-type='application/protobuf'Sets the Firestore direct-event payload encoding
--service-account--service-account='eventarc-firestore@bq-wh-nb.iam.gserviceaccount.com'Specifies the identity Eventarc uses to invoke the destination
--database--database='main'Targets the correct named Firestore database when listing or describing admin operations

PowerShell / Linux | gcloud | offload history and analytical workloads

The clean Firestore pattern is to keep current operational truth in Firestore and move detail history elsewhere.

Export operational history for BigQuery or offline processing

Before historical analysis, before deleting old records, or when building a warehouse view of operational metadata. It is typically triggered by firestore is holding data that is still useful, but no longer belongs on the low-latency hot path. gcloud CLI, state-changing. Requires a real Cloud Storage bucket, billing, and appropriate permissions. Snapshot operational history into a portable format that can be loaded into BigQuery or archived in Cloud Storage.

Export is billed and should be scoped

Firestore export incurs one read operation per exported document. Export only the collection groups you actually need.

Export before aggressive cleanup

If you plan to delete old run history, backfill manifests, or deduplication records, export them first so historical analysis and forensics do not disappear with the cleanup.

Export pipeline_runs from the archived main database pattern to a verified Cloud Storage prefix.

gcloud firestore export 'gs://YOUR_EXISTING_BUCKET/firestore/main/pipeline-runs-2026-04-13' \
  --database='main' \
  --collection-ids='pipeline_runs'

Firestore documentation explicitly notes that managed Firestore exports can be loaded into BigQuery. Keep the export narrow and let BigQuery own the analytical use case.

Run a managed bulk delete for bounded operational collections

When TTL is insufficient for urgency, or when you need a controlled cleanup of one or more operational collection groups. It is typically triggered by A collection group such as replay_manifests or run_debug_payloads must be cleared in bulk. gcloud CLI, state-changing. Requires billing and Firestore bulk admin permission. Delete large operational data sets without writing custom deletion code.

Bulk delete is destructive and not retroactive to later writes

Firestore’s managed bulk delete service deletes documents that match when the operation starts. Documents added or modified after the operation begins are not part of that delete set.

Use bulk delete for exceptional cleanup, not as your normal lifecycle policy

For steady-state operations, prefer TTL on bounded collections and export-plus-archive for long retention. Reserve bulk delete for controlled cleanup events.

Bulk delete two explicitly named collection groups from the main database.

gcloud firestore bulk-delete \
  --database='main' \
  --collection-ids='replay_manifests','run_debug_payloads'

Track the operation using the operation name returned by the initiating command. In named-database environments, pass --database explicitly if you later use gcloud firestore operations list or describe.

FlagSyntaxDescription
--database--database='main'Targets the named Firestore database
--collection-ids--collection-ids='pipeline_runs'Restricts export or bulk delete to selected collection groups

Warnings, Limitations, And Anti-Patterns

These are the ways teams accidentally turn Firestore from a clean state service into a confused pseudo-stream or pseudo-warehouse.

Firestore | anti-patterns | common pipeline design mistakes

Anti-patternWhy it breaks downBetter pattern
Using Firestore as the event busNo native replay, backpressure, or queue semanticsUse Pub/Sub for transport and Firestore for state
Treating Eventarc delivery as exactly-onceRetries and duplicates happenMake handlers idempotent and store dedup keys
Streaming large analytical history out of Firestore for dashboardsCosts rise with document reads and scansMaterialize summaries in Firestore and move history to BigQuery
Long-lived backend listeners for server orchestrationHarder to reason about lifecycle and cost than explicit eventsUse Eventarc or Pub/Sub for server-side reactions
Keeping ephemeral collections foreverFirestore becomes a graveyard of old operational metadataAdd TTL, export history, and keep retention bounded
Writing every event as a large document with sequential IDsHotspots, index fanout, and rising write latencyUse scattered IDs, smaller documents, and companion services for heavy history

Firestore | platform boundary | what Firestore should not pretend to be

Firestore is not the entire pipeline

Firestore is excellent at current state and lightweight operational metadata. It is not:

  • A replayable message broker
  • A warehouse for broad scans
  • A durable log of every event forever
  • A substitute for BigQuery, Pub/Sub, or Dataflow

Keep responsibilities clean

A maintainable design usually looks like this:

  • Pub/Sub for transport
  • Dataflow for throughput and transformation
  • Firestore for current control-plane truth
  • BigQuery for analytical and historical views

Recommendations And Best Practices

These defaults keep Firestore useful in pipelines instead of letting it absorb responsibilities it should not own.

Firestore | production defaults | high-signal operating guidance

RecommendationWhy it matters
Keep one compact current-state document per pipeline, entity, or workflow boundaryThis makes reads cheap and the control plane easy to reason about
Add a stable idempotency key to every event-driven write pathRetries and duplicate delivery become safe instead of dangerous
Put expires_at on ephemeral operational collectionsTTL keeps transient metadata bounded
Store detailed history outside FirestoreBigQuery or Cloud Storage handle analytical retention far better
Use Firestore for summary documents, not for every raw eventThis reduces read cost and index pressure
Keep region choice explicit and co-locate compute when possibleTrigger and write latency depend on location alignment
Make replay workflows explicit with manifests and checkpointsIncident recovery is easier when replay state is first-class
Use schema_version and owner fields on operational documentsThese fields reduce ambiguity during migrations and incidents

Data Engineering Scenarios

The scenarios below are the practical patterns that fit Firestore well in real pipelines.

Firestore | orchestration metadata | Composer, Cloud Run jobs, and control loops

When multiple schedulers, jobs, or operators need the same current operational truth, Firestore is a clean coordination store.

Use caseDocument patternNotes
Current DAG or job statuspipeline_runs/{run_id}Good for operator dashboards and current failure triage
Shared runtime configconfig/{pipeline_name}Read at job start and optionally cache with a short TTL in memory
Backfill coordinationbackfills/{backfill_id}Track state, owner, time range, and current phase
Lease or coordination lockleases/{resource_id}Add owner, expiry, and last heartbeat fields

Example orchestration metadata document for a backfill run.

{
  "schema_version": 1,
  "pipeline": "daily-stocks-ingest",
  "backfill_id": "bf-2026-04-q2",
  "status": "running",
  "range_start": "2026-04-01T00:00:00Z",
  "range_end": "2026-04-07T23:59:59Z",
  "owner": "composer/dag-data-platform-backfill",
  "updated_at": "2026-04-13T12:00:00Z",
  "expires_at": "2026-05-13T12:00:00Z"
}

Firestore | idempotency and deduplication | safe repeat processing

This is where Firestore often earns its keep in event-driven systems: one compact document per deduplication decision.

PatternFirestore roleWhat to watch
Idempotency key registerStores one record per processed business keyAdd TTL so the set stays bounded
Replay manifestStores the replay window, operator, and statusSeparate replay state from the main checkpoint
Deduplication tokenStores the key and processing resultMake sure the key represents the business duplicate boundary

Example idempotency document for an event-driven ingestion path.

{
  "schema_version": 1,
  "idempotency_key": "orders:2026-04-13T11:30:00Z:order-88123",
  "status": "applied",
  "applied_at": "2026-04-13T11:30:07Z",
  "producer": "pubsub/topic/orders",
  "consumer": "cloud-run/order-normalizer",
  "expires_at": "2026-04-20T11:30:07Z"
}

Firestore | hot and cold split | keeping the right data in the right store

This pattern avoids the common mistake of keeping every operational detail in Firestore forever.

LayerBest storeWhat belongs there
Hot operational stateFirestoreCurrent config, checkpoint, run status, dedup keys
Transport and fan-outPub/SubMessages and delivery buffering
Stream or batch transformationDataflowWindowing, enrichment, dual writes, high-throughput transforms
Historical analyticsBigQueryTrend analysis, audits, cost analysis, long-term run history
Large artifacts or raw payloadsCloud StorageExport files, payload archives, replay bundles

Firestore | incident recovery | replay, restore, and rollback markers

Incidents are easier when recovery state is explicit instead of implied in logs or in someone’s memory.

Recovery concernFirestore roleCompanion control
Track what was replayedStore a replay manifest documentUse Pub/Sub retention, export, backup, or PITR as the replay source
Track whether the recovered state is validatedStore a restore-validation documentUse a new restored database and application checks before cutover
Coordinate rollback or cutoverStore cutover state and ownerPair with runbooks and deployment approvals

Troubleshooting And Common Failures

Most operational failures are one of five things: prerequisites missing, location mismatch, duplicate delivery, state drift, or cost drift.

Firestore | pipeline failure modes | symptoms, confirmation, and action

SymptomLikely causeHow to confirmAction
Eventarc trigger never firesEventarc or Cloud Run API not enabled, or trigger path mismatchRe-run the enabled-service check and inspect trigger filtersEnable missing APIs and fix the document path pattern
Duplicate downstream processingAt-least-once delivery plus non-idempotent handlerInspect dedup or side-effect recordsAdd or fix the idempotency key path
Firestore costs rise unexpectedlyBroad scans, large run-history collections, or excessive indexingReview collection size, query shapes, and index configMove history to BigQuery, add TTL, exempt non-query fields
Pipeline state looks staleJobs are not updating current-state documents consistentlyCompare pipeline logs and the summary documentsMake state updates explicit and durable at key workflow boundaries
Backfill collides with live processingShared state has no explicit lease or replay boundaryInspect backfill manifest, checkpoint, and lease documentsAdd leases, replay manifests, and ownership fields
Trigger creation fails by regionTrigger or Cloud Run service is not aligned to Firestore locationRe-check gcloud firestore databases describe --database='main'Align trigger location and service region to europe-west1

Decision Matrix Or When-To-Use Guidance

Use this matrix to choose the right Firestore-centered pattern.

NeedRecommended patternWhy
React to a document change with lightweight workFirestore + Eventarc + Cloud RunThe state change itself is the event boundary
Buffer and fan out many eventsPub/Sub + Firestore statePub/Sub handles transport while Firestore stores current state
High-throughput streaming with hot and cold outputsPub/Sub + Dataflow + Firestore + BigQueryEach service owns the layer it is best at
Current orchestration metadata across jobs and operatorsFirestore + Composer / Cloud Run jobsFirestore is a simple shared control-plane store
Historical analysis of run dataFirestore export or dual-write to BigQueryBigQuery is the analytical destination

Quick Reference

The table below preserves the archived project readiness captured on 2026-04-13. It is historical reference only because the original project has been removed.

ItemCurrent valueOperational implication
Active projectbq-wh-nbAll default gcloud commands target this project unless overridden
Firestore databasemainTrigger and admin commands must target a named database
Firestore locationeurope-west1Eventarc and Cloud Run placement should align with this region
Enabled relevant APIsfirestore.googleapis.com, pubsub.googleapis.com, bigquery.googleapis.comFirestore, Pub/Sub, and BigQuery patterns are currently platform-ready
Missing relevant APIseventarc.googleapis.com, run.googleapis.com, dataflow.googleapis.comEventarc and Dataflow patterns need project-level provisioning first

The shortest safe integration checklist is:

  1. Confirm the active project and named Firestore database.
  2. Confirm the Firestore location.
  3. Confirm the required service APIs are enabled.
  4. Confirm the destination service account and region.
  5. Only then create triggers, exports, or bulk operations.