Introduction to Firestore Monitoring
Monitoring Firestore means continuously observing the performance, usage patterns, and health of your Firestore database through metrics, visual dashboards, and automated alerts. Firestore runs as a fully managed service on Google Cloud Platform, which means much of the operational heavy lifting—replication, sharding, backups—is handled for you. However, your application's interaction with Firestore remains entirely your responsibility. Without proper monitoring, you risk unexpected bills from read spikes, degraded user experiences from slow queries, or silent failures that go undetected for hours.
Effective monitoring gives you a real-time window into how your database is performing. It transforms raw telemetry into actionable insights: you can catch a runaway loop that's hammering reads before your bill skyrockets, detect a newly deployed feature that's triggering slow queries, or verify that your latest index deployment actually improved performance. In short, monitoring closes the gap between "it works in development" and "it works reliably in production."
Why Firestore Monitoring Matters
Firestore's pricing model ties directly to usage—reads, writes, deletes, and storage. Without visibility into these metrics, cost becomes unpredictable. Beyond cost, there are hard operational limits: maximum writes per second per database, contention on hot documents, and query rejection when index limits are exceeded. Monitoring surfaces these issues before they become outages. Here are the primary reasons to invest in monitoring:
- Cost control – Identify which collections or operations drive the most reads and writes, and spot anomalies early.
- Performance optimization – Track query latency, index utilization, and slow-performing queries to keep your app responsive.
- Reliability – Detect spikes in errors, rejections, or throttling events that indicate your database is under stress.
- Capacity planning – Understand growth trends in storage and document counts to anticipate future needs.
- Compliance and auditing – Maintain an audit trail of administrative operations and access patterns.
Key Firestore Metrics You Should Track
Google Cloud Monitoring automatically collects a rich set of Firestore metrics. These are grouped into several categories. Understanding what each metric represents is the foundation of building useful dashboards and alarms.
Document Operation Metrics
These metrics count every read, write, and delete operation against your documents. They are the primary drivers of your bill and the best indicators of workload changes.
firestore.googleapis.com/document/read_count– Total document reads (including queries that read multiple documents).firestore.googleapis.com/document/write_count– Total document writes (creates, updates, sets).firestore.googleapis.com/document/delete_count– Total document deletions.
Each of these metrics can be filtered by database_id and collection_id, allowing you to pinpoint which collections are the most active or expensive.
Query Performance Metrics
Firestore tracks how your queries behave, including whether indexes are being used efficiently and how long queries take to complete.
firestore.googleapis.com/api/request_count– Total API requests, broken down by operation type (GetDocument, ListDocuments, RunQuery, etc.).firestore.googleapis.com/query/index_utilization– Shows whether queries are using indexes optimally. A low index utilization ratio means Firestore is scanning more documents than necessary.firestore.googleapis.com/query/latency– End-to-end latency for query execution, measured in milliseconds.
Error and Rejection Metrics
Errors can be client-side (bad requests) or server-side (throttling, unavailable resources). Tracking errors helps you distinguish between a bug in your code and a genuine infrastructure problem.
firestore.googleapis.com/api/error_count– Count of API errors, filterable by error code (e.g.,ABORTED,UNAVAILABLE,DEADLINE_EXCEEDED).firestore.googleapis.com/api/rejection_count– Requests rejected due to throttling or exceeding limits.
Storage and Infrastructure Metrics
firestore.googleapis.com/storage/total_bytes– Total storage used across all documents, indexes, and metadata.firestore.googleapis.com/storage/doc_count– Total number of documents stored.
Accessing Firestore Metrics
There are three primary paths to view and interact with Firestore metrics: the Firebase Console, the Google Cloud Console (Cloud Monitoring), and programmatic access via the Cloud Monitoring API.
Firebase Console Metrics Dashboard
The Firebase Console provides a streamlined, Firestore-specific view of your usage. Navigate to Firestore > Usage to see charts for reads, writes, deletes, and storage over a rolling 24-hour window. This is ideal for quick checks and spotting immediate anomalies. However, the Firebase Console only shows a single database at a time and has limited historical retention (typically 30 days for aggregated data).
Google Cloud Monitoring (Cloud Console)
For advanced analysis, go to the Google Cloud Console and open Monitoring > Metrics Explorer. Here you can query any Firestore metric, apply filters, group by resource labels, and view data across arbitrary time ranges. This is also where you create alerting policies and custom dashboards that persist across sessions.
To find Firestore metrics in Metrics Explorer:
- In the Select a metric dropdown, search for "Firestore".
- Choose a metric like
firestore.googleapis.com/document/read_count. - Use the Filter field to narrow by
database_idorcollection_id. - Set the aggregation method (sum, mean, rate) and alignment period.
- Click Save chart to dashboard to persist the visualization.
Cloud Monitoring API
For programmatic access, the Cloud Monitoring API lets you query time series data directly. This is essential for embedding Firestore metrics into your own tooling, CI/CD pipelines, or custom reporting systems.
Below is a Node.js example that queries the read_count metric for a specific database over the last hour, using the @google-cloud/monitoring client library:
const { MetricServiceClient } = require('@google-cloud/monitoring');
async function getFirestoreReadCount(projectId, databaseId) {
const client = new MetricServiceClient();
const projectPath = client.projectPath(projectId);
const now = new Date();
const oneHourAgo = new Date(now.getTime() - 60 * 60 * 1000);
const request = {
name: projectPath,
filter: `metric.type = "firestore.googleapis.com/document/read_count"` +
` AND resource.label.database_id = "${databaseId}"`,
interval: {
startTime: {
seconds: Math.floor(oneHourAgo.getTime() / 1000),
},
endTime: {
seconds: Math.floor(now.getTime() / 1000),
},
},
aggregation: {
alignmentPeriod: {
seconds: 60,
},
perSeriesAligner: 'ALIGN_SUM',
},
view: 'FULL',
};
const [timeSeries] = await client.listTimeSeries(request);
for (const series of timeSeries) {
console.log(`Metric: ${series.metric.type}`);
for (const point of series.points) {
const endTime = point.interval.endTime.seconds;
const value = point.value.int64Value || point.value.doubleValue;
console.log(` Time: ${new Date(endTime * 1000).toISOString()}, Value: ${value}`);
}
}
return timeSeries;
}
// Usage
getFirestoreReadCount('my-project-id', '(default)');
For environments where you prefer REST calls directly, you can use the timeSeries.list endpoint. Here's an equivalent query using curl:
curl -X GET \
"https://monitoring.googleapis.com/v3/projects/my-project-id/timeSeries" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-d "filter=metric.type%3D%22firestore.googleapis.com%2Fdocument%2Fread_count%22%20AND%20resource.label.database_id%3D%22(default)%22" \
-d "interval.startTime=$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ)" \
-d "interval.endTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-d "aggregation.alignmentPeriod=60s" \
-d "aggregation.perSeriesAligner=ALIGN_SUM"
Setting Up Alarms and Alerts
Alerts turn passive monitoring into an active safety net. Instead of staring at dashboards waiting for something to break, you configure conditions that notify you—via email, SMS, Slack, PagerDuty, or webhook—when metrics cross defined thresholds.
Using Cloud Monitoring Alerting Policies
An alerting policy in Cloud Monitoring consists of three parts: a condition (what triggers the alert), a notification channel (how you get notified), and optional documentation (runbook instructions included in the alert).
You can create alerting policies through the Cloud Console UI, via gcloud CLI, or through the API. Below is a gcloud example that creates an alert when document reads spike more than 50% above the baseline over a 5-minute window:
gcloud alpha monitoring policies create \
--display-name="Firestore Read Spike Alert" \
--condition-display-name="High read count anomaly" \
--condition-filter='metric.type="firestore.googleapis.com/document/read_count" resource.label.database_id="(default)"' \
--condition-aggregation-alignment-period="300s" \
--condition-aggregation-per-series-aligner="ALIGN_RATE" \
--condition-duration="300s" \
--condition-trigger-percent="50" \
--condition-trigger-comparison="COMPARISON_GT" \
--condition-trigger-baseline="BASELINE_PREVIOUS_GENERATION" \
--notification-channels="projects/my-project-id/notificationChannels/1234567890" \
--documentation-text="Firestore read count has spiked significantly. Check for deployment changes, traffic surges, or runaway queries. Runbook: https://wiki.internal/firestore-read-spike"
For a simpler threshold-based alert (not anomaly detection), you can use the absolute value comparison. Here's how to create an alert when errors exceed 10 per minute:
gcloud alpha monitoring policies create \
--display-name="Firestore High Error Rate" \
--condition-display-name="Error rate > 10/min" \
--condition-filter='metric.type="firestore.googleapis.com/api/error_count" resource.label.database_id="(default)"' \
--condition-aggregation-alignment-period="60s" \
--condition-aggregation-per-series-aligner="ALIGN_RATE" \
--condition-threshold-value="10" \
--condition-threshold-comparison="COMPARISON_GT" \
--condition-duration="120s" \
--notification-channels="projects/my-project-id/notificationChannels/1234567890"
Common Alert Scenarios
Here are practical alert configurations that cover the most critical monitoring needs for a production Firestore deployment:
-
Read cost spike – Alert when the sum of document reads exceeds your daily budget threshold over a rolling 30-minute window. Use
ALIGN_SUMaggregation and a threshold like 100,000 reads per 30 minutes. -
Error rate surge – Alert when
api/error_countwith error codeDEADLINE_EXCEEDEDorUNAVAILABLEexceeds 5% of total requests. This catches infrastructure degradation quickly. -
Index utilization drop – Alert when
query/index_utilizationfalls below 0.8 (80% utilization), meaning queries are scanning more documents than indexed. This often indicates a missing composite index. -
Write throttling – Alert when
api/rejection_countrises above zero, as this means your write throughput is hitting the database's soft limits.
Notification Channels
Before creating alerts, set up notification channels. Common channels include email, Slack (via webhook), PagerDuty, and SMS. You can create them via the Cloud Console under Monitoring > Alerting > Edit Notification Channels, or programmatically:
gcloud alpha monitoring channels create \
--display-name="Engineering Slack" \
--type="slack" \
--slack-auth-token="xoxb-your-token" \
--slack-channel="#firestore-alerts"
Building Custom Dashboards
Dashboards give you a unified view of Firestore health. Rather than clicking through multiple screens, a well-designed dashboard surfaces all critical metrics at a glance.
Cloud Monitoring Dashboards via Console
In the Cloud Console, navigate to Monitoring > Dashboards and click Create Dashboard. Add charts one by one, selecting Firestore metrics and configuring filters, aggregation, and visualization type (line chart, stacked area, heatmap, or table). A good production dashboard typically includes:
- Operations overview – Stacked area chart showing reads, writes, and deletes per minute, filtered by database.
- Error breakdown – Line chart of error count grouped by error code (
ABORTED,UNAVAILABLE,DEADLINE_EXCEEDED). - Latency percentiles – Chart showing p50, p95, and p99 query latency over time.
- Storage growth – Daily snapshot of total storage bytes and document count.
- Top collections by cost – If you filter read/write metrics by
collection_id, you can build a table listing the most active collections.
Programmatic Dashboard Creation
You can create dashboards via the Cloud Monitoring API, which is useful for infrastructure-as-code setups. The following example defines a dashboard with a single chart that shows reads and writes side-by-side using the REST API:
curl -X POST \
"https://monitoring.googleapis.com/v3/projects/my-project-id/dashboards" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-d '{
"displayName": "Firestore Operations Dashboard",
"dashboardFilters": [
{
"labelKey": "resource.label.database_id",
"templateVariable": "DATABASE_ID",
"defaultValue": "(default)"
}
],
"mosaicLayout": {
"columns": 2,
"tiles": [
{
"title": "Document Reads (per minute)",
"widget": {
"title": "Reads",
"xyChart": {
"dataSets": [
{
"timeSeriesQuery": {
"timeSeriesFilter": {
"filter": "metric.type=\"firestore.googleapis.com/document/read_count\" resource.label.database_id=\"${DATABASE_ID}\"",
"aggregation": {
"alignmentPeriod": "60s",
"perSeriesAligner": "ALIGN_RATE"
}
}
},
"plotType": "LINE"
}
],
"chartOptions": {
"displayHorizontal": false
}
}
}
},
{
"title": "Document Writes (per minute)",
"widget": {
"title": "Writes",
"xyChart": {
"dataSets": [
{
"timeSeriesQuery": {
"timeSeriesFilter": {
"filter": "metric.type=\"firestore.googleapis.com/document/write_count\" resource.label.database_id=\"${DATABASE_ID}\"",
"aggregation": {
"alignmentPeriod": "60s",
"perSeriesAligner": "ALIGN_RATE"
}
}
},
"plotType": "LINE"
}
],
"chartOptions": {
"displayHorizontal": false
}
}
}
}
]
}
}'
Exporting Metrics to External Tools
Many teams run their own monitoring stack (Datadog, Grafana, Prometheus). You can export Cloud Monitoring metrics to these tools using the cloud-monitoring-export connectors or by polling the API periodically. Here's a Python script that pulls the last 5 minutes of read/write counts and emits them as structured logs, which can be ingested by any log-based monitoring system:
import time
from google.cloud import monitoring_v3
from datetime import datetime, timedelta
def fetch_firestore_metrics(project_id, database_id="(default)"):
client = monitoring_v3.MetricServiceClient()
project_name = f"projects/{project_id}"
now = datetime.utcnow()
start = now - timedelta(minutes=5)
metrics_to_fetch = [
"firestore.googleapis.com/document/read_count",
"firestore.googleapis.com/document/write_count",
"firestore.googleapis.com/document/delete_count",
"firestore.googleapis.com/api/error_count",
]
results = {}
for metric_type in metrics_to_fetch:
request = {
"name": project_name,
"filter": f'metric.type="{metric_type}" '
f'resource.label.database_id="{database_id}"',
"interval": {
"start_time": {"seconds": int(start.timestamp())},
"end_time": {"seconds": int(now.timestamp())},
},
"aggregation": {
"alignment_period": {"seconds": 60},
"per_series_aligner": monitoring_v3.Aggregation.Aligner.ALIGN_SUM,
},
}
time_series = client.list_time_series(request=request)
total = 0
for ts in time_series:
for point in ts.points:
value = point.value.int64_value or point.value.double_value or 0
total += value
short_name = metric_type.split("/")[-1]
results[short_name] = total
return results
# Run every 5 minutes in a background loop
while True:
metrics = fetch_firestore_metrics("my-project-id")
print(f"[{datetime.utcnow().isoformat()}] METRICS: {metrics}")
time.sleep(300)
Advanced: Custom Metrics and Client-Side Monitoring
The built-in server-side metrics are powerful, but they don't capture everything. For example, they won't tell you which specific queries in your application are slow—they only show aggregate latency. To fill this gap, you can instrument your application code to emit custom metrics or structured logs.
Tracking Query Performance from the Client SDK
The following example uses the Firestore Node.js Admin SDK to wrap a query execution with timing instrumentation, then writes the result to Cloud Logging where it can be queried later:
const admin = require('firebase-admin');
const { Logging } = require('@google-cloud/logging');
admin.initializeApp();
const db = admin.firestore();
const logging = new Logging();
const log = logging.log('firestore-query-performance');
async function timedQuery(collectionName, queryFn) {
const start = Date.now();
let result;
let error = null;
try {
result = await queryFn();
} catch (err) {
error = err.message || err.code;
}
const durationMs = Date.now() - start;
const documentCount = Array.isArray(result) ? result.length : (result ? 1 : 0);
// Write structured log entry for later analysis
const entry = log.entry(
{
resource: { type: 'global' },
severity: error ? 'ERROR' : 'INFO',
},
{
collection: collectionName,
durationMs,
documentCount,
error,
timestamp: new Date().toISOString(),
}
);
await log.write(entry);
if (error) throw new Error(error);
return result;
}
// Usage: timed query for recent orders
const orders = await timedQuery('orders', () =>
db.collection('orders')
.where('status', '==', 'pending')
.where('createdAt', '>', new Date(Date.now() - 86400000))
.limit(50)
.get()
);
console.log(`Retrieved ${orders.size} pending orders`);
Creating Custom Cloud Monitoring Metrics
You can also write custom metrics directly to Cloud Monitoring using the projects.timeSeries.create endpoint. This allows you to define entirely new metric types—for example, tracking cache hit rates for a Firestore fronting cache layer, or counting business-level events that correlate with database load.
curl -X POST \
"https://monitoring.googleapis.com/v3/projects/my-project-id/timeSeries" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-d '{
"timeSeries": [
{
"metric": {
"type": "custom.googleapis.com/firestore/cache_hit_rate",
"labels": {
"collection": "users"
}
},
"resource": {
"type": "global",
"labels": {}
},
"metricKind": "GAUGE",
"valueType": "DOUBLE",
"points": [
{
"interval": {
"endTime": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
},
"value": {
"doubleValue": 0.87
}
}
]
}
]
}'
Once your custom metric is registered (it registers automatically on first write), you can chart it in dashboards, alert on it, and query it alongside native Firestore metrics.
Best Practices for Firestore Monitoring
Proactive vs. Reactive Monitoring
Don't wait for users to report slowdowns. Set up alerts on trending indicators—metrics that degrade before an outright failure occurs. For example, a gradual increase in p95 query latency over several hours might indicate an emerging hot shard. Catching it early lets you redistribute load before latency spikes into the seconds.
Cost-Aware Monitoring
Firestore costs scale with usage, so monitoring should include cost projections. Use the read_count and write_count metrics multiplied by your pricing tier to estimate daily spend. Build a dashboard widget that shows projected daily cost based on the current rate of operations, and alert when the projection exceeds your budget by 20%.
SLO-Based Alerting
Define Service Level Objectives (SLOs) for your Firestore-dependent operations—for instance, "99.9% of queries complete within 500ms." Use the query/latency metric to track compliance. Alert only when your error budget is being burned too quickly, rather than on every individual latency spike. This reduces alert fatigue while still protecting the user experience.
Separate Alerts by Severity
Not every metric anomaly requires waking someone up at 3 AM. Use severity tiers:
- Critical (P1) – Error rate > 5%, write rejections > 0, or complete query failures. Immediate pager notification.
- Warning (P2) – Latency p95 > 1s, cost projection > budget, or index utilization < 70%. Notification during business hours or via non-urgent channels.
- Info (P3) – Storage growth acceleration, new collection activity patterns. Logged to dashboard for periodic review.
Retention and Historical Analysis
Cloud Monitoring retains metrics for different durations based on resolution. High-resolution data (aligned to 1-minute intervals) is kept for 6 weeks; lower-resolution data (aligned to 1-day intervals) stays for longer. For long-term trend analysis, consider exporting metrics to BigQuery or a time-series database where you can run queries across months of data.
Test Your Alerts
An alert that never fires might be misconfigured. Periodically trigger your alerts intentionally—for example, by running a script that generates a burst of reads against a test collection—to verify that notifications reach the right channels with the expected payload and runbook links.
Document Your Dashboards
Each dashboard tile should have a clear title and, where possible, a description that explains what the metric means and what to do if it looks unusual. This reduces the time on-call engineers spend interpreting charts during an incident. Use the documentation field in alerting policies to link directly to runbooks.
Conclusion
Monitoring Firestore is not a one-time setup task—it is an evolving practice that matures alongside your application. Start by connecting to the built-in Cloud Monitoring metrics and setting up a handful of essential alerts: cost spikes, error surges, and latency degradation. From there, build dashboards that give you a single-pane-of-glass view of database health. As your application grows, layer on client-side instrumentation for query-level visibility, define SLOs to reduce alert noise, and export long-term data for trend analysis. The combination of native GCP metrics, custom instrumentation, and well-tuned alerting policies transforms Firestore from a black-box managed service into a transparent, predictable, and cost-controlled component of your production stack.