What Is Firestore? Google Cloud's NoSQL Document Database Explained
Firestore is Google Cloud’s serverless NoSQL document database. Instead of tables and rows, you store data as documents in collections. It scales automatically, has no infrastructure to manage, and is well-suited to mobile apps, web applications, and any workload where data structure varies between records. It also comes with real constraints that catch developers off-guard: no SQL joins, index-dependent queries, and billing tied directly to how many documents you read or write.
Firestore in plain English
If you have used a relational database before, the rough mental model is: collections are like tables and documents are like rows. But the comparison only goes so far.
A document is a named bag of fields: strings, numbers, booleans, timestamps,
arrays, nested objects, or references to other documents. Each document has a
unique ID within its collection. There is no fixed schema, so two documents
in the same collection can have completely different fields. One user document
might have a photoUrl field; another might not. Firestore does
not care.
Collections hold documents. Documents can hold subcollections. A
users collection might contain one document per user, and each
of those documents might contain an orders subcollection. You
get real hierarchical structure without forcing everything into flat tables.
What you cannot do: filter on arbitrary fields without an index, join across collections at query time, or run analytical aggregations over millions of documents. Firestore trades SQL flexibility for fast, predictable performance at scale. That trade-off works well for app-centric workloads and poorly for anything requiring complex relational queries.
Think of a relational database as a spreadsheet. Every row has the same columns, and you can sort, filter, or combine sheets using formulas and joins. Firestore is more like a filing cabinet. Each drawer (collection) holds index cards (documents), and each card can contain whatever information is relevant to that specific item. Cards in the same drawer do not have to follow the same template. What you give up is the ability to run a formula across all cards at once in an open-ended way. You can only look up cards you have specifically indexed.
How Firestore organises data
Understanding the data model matters more in Firestore than in most databases, because your data structure directly determines which queries are possible. Unlike SQL, you cannot invent a new query later and assume an index exists for it.
Documents are sets of key-value pairs, similar to a JSON object. Field types include strings, numbers, booleans, timestamps, geographic points, byte arrays, arrays, and nested maps. Each document has a unique ID, either auto-generated by Firestore or assigned by you.
Collections are containers for documents. You do not create a collection explicitly. You just write a document to a collection path and it appears. A collection can hold any number of documents.
Subcollections let a document contain its own nested
collection. For example: users/{userId}/orders/{orderId}.
This is a natural way to model one-to-many relationships. A user’s
orders live directly under that user’s document, rather than in a
separate table with a foreign key.
Indexes are how Firestore queries work. Single-field indexes are created automatically for every field in every document. Queries that filter or sort on more than one field require a composite index, which you define and Firestore builds in the background. If you run a query that needs a missing index, Firestore returns an error with a direct link to create it. That is helpful during development, but it also means you need to plan your indexes before going to production.
Think of an index at the back of a textbook. You can only look up topics that are listed there. If something is not in the index, you cannot jump directly to the right page — you would have to read the whole book. Firestore queries work the same way. A query can only find documents using fields that have been indexed. No index means no fast lookup; Firestore will refuse the query entirely rather than do a slow full scan.
Real-time listeners are one of Firestore’s most useful features for app developers. In Native mode, clients can subscribe to a document or collection and receive updates automatically when data changes, without polling. This makes features like live chat, collaborative editing, and notification feeds straightforward to build.
The Firestore Data Model page goes deeper on structuring documents, subcollections, and denormalisation patterns. The Firestore Queries page covers indexes and query design in detail.
Native mode vs Datastore mode
When you create a Firestore database, you choose between two modes. This choice is permanent and cannot be changed after the database exists.
Native mode is the current generation. Choose this for any new project. It supports real-time listeners, offline data sync via mobile and web SDKs, and multi-document atomic transactions.
Datastore mode is a compatibility layer for applications originally built on Cloud Datastore, the older GCP NoSQL service. Use this only if you are migrating an existing Datastore application. It has no real-time listeners and no reason to be picked for new projects.
Choose Native mode. There is no scenario where Datastore mode is preferable for new work. The choice is permanent, so get it right at the start.
Creating a Firestore database
# Create a Firestore database in Native mode
gcloud firestore databases create \
--location=europe-west2 \
--type=firestore-native
# Create a Firestore database in Datastore mode (legacy migrations only)
gcloud firestore databases create \
--location=europe-west2 \
--type=datastore-mode
# List all Firestore databases in the project
gcloud firestore databases listThe —location flag sets where your data is stored. Firestore
supports both regional and multi-regional locations. Multi-regional locations
such as eur3 (Europe) or nam5 (North America)
replicate data across multiple regions automatically, at higher cost. Regional
locations store data in a single region.
A GCP project can have more than one Firestore database. The default is
named (default). Named databases are useful for separating
production and staging environments, or for multi-tenant architectures
where each tenant gets an isolated database.
When Firestore is the right choice
Firestore earns its place in the right workloads. Here is where it genuinely works well:
Mobile app user profiles and settings. Each user gets their own document. Fields vary between users. You can add new profile fields without any schema migration. Client SDKs handle reads and writes cleanly.
Chat and collaboration features. Messages, threads, and presence data fit naturally into Firestore’s hierarchical document model. Real-time listeners mean clients receive new messages without polling. Many team tools and messaging apps use this pattern.
Content-driven applications. Blog posts, articles, and CMS content often have varying fields per item. A news article with a video has different fields than a text-only piece. Firestore handles inconsistent fields across documents without complaint.
Product catalogues with flexible attributes. A shoe needs
sizeandcolour; a laptop needsramandcpuSpeed. With Firestore, each product document carries only the fields relevant to it, within a single collection.Offline-capable client applications. Firestore’s mobile and web SDKs cache data locally. If a device loses connectivity, the app continues to function against the local cache and syncs when connectivity returns. This is built-in behaviour, not custom code you have to write.
Low-overhead backends for small teams. Firestore is serverless. There are no instances to size, no connection pools to manage, and no maintenance windows to schedule. If you want to ship quickly without spending time on database infrastructure, it fits.
Choose something else when…
Firestore is not the right answer for every data problem. Be honest about whether your workload fits before you commit to it.
Your queries need joins. Firestore has no joins. Combining data from multiple collections requires multiple round-trip reads at the application layer. If your data model is inherently relational, use Cloud SQL from the start.
You need complex aggregations or analytics. Counting, summing, and grouping across millions of documents is not what Firestore is built for. It has limited aggregation support (count, sum, average on basic queries), but anything seriously analytical belongs in BigQuery. Firestore can export to BigQuery automatically, making them complementary.
You have very high write throughput to a single document. Firestore limits writes to roughly one per second per document. A shared counter, a real-time leaderboard, or any single document acting as a write bottleneck will hit this ceiling.
Your workload is time-series or append-heavy at scale. Ingesting millions of sensor readings, log entries, or events per hour is better handled by Bigtable, which is designed specifically for high-throughput sequential writes at petabyte scale.
You need full-text search. Firestore cannot do substring matching or full-text search natively. For that, integrate with a dedicated search service or export to BigQuery.
Relational integrity must be enforced at the database layer. Firestore has no foreign key constraints. If consistency between related documents needs to be guaranteed by the database rather than your application code, use a relational database.
Firestore vs Cloud SQL, Bigtable, and BigQuery
Firestore vs relational databases
The core difference is the data model. Relational databases enforce a schema: you define columns upfront, every row must conform, and constraints like NOT NULL and FOREIGN KEY are enforced by the database itself. Firestore enforces nothing. Documents in the same collection can have completely different fields without error.
Relational databases give you SQL: arbitrary queries, joins across tables, GROUP BY, window functions, and full aggregation. Firestore gives you fast, indexed lookups against a predefined set of queries. If you know your query patterns upfront and none of them need joins, Firestore is often faster and simpler to operate. If your query needs are exploratory or open-ended, SQL wins.
Firestore vs Cloud SQL
Data model: Firestore uses documents and collections with a flexible schema. Cloud SQL uses tables and rows with a fixed, enforced schema.
Queries: Firestore uses index-driven lookups with no joins. Cloud SQL supports full SQL including joins, subqueries, and aggregations.
Scaling: Firestore scales automatically. Cloud SQL scales by resizing the instance and adding read replicas.
Operations: Firestore is serverless with no infrastructure to manage. Cloud SQL requires choosing an instance type and managing storage and backups.
Pricing: Firestore charges per operation. Cloud SQL charges for the running instance regardless of load.
Choose Firestore for mobile and web apps with document-oriented data, flexible schemas, and real-time requirements. Choose Cloud SQL when your data is relational, your queries need joins, or you are migrating an existing relational application.
Firestore vs Bigtable
Bigtable is a wide-column NoSQL database designed for petabyte-scale, high-throughput workloads: time-series, IoT ingestion, event logs. It is significantly more expensive and complex to operate. A minimum production cluster costs several hundred dollars per month before you store a single byte. If your dataset is under 1 TB, Bigtable is not justified. Firestore is the right NoSQL choice for most application workloads. Bigtable is for high-throughput sequential data at scale. See the Bigtable Overview for detail.
Firestore vs BigQuery
BigQuery is an analytical warehouse, not an application database. It is designed for running large SQL queries over billions of rows, not for serving live application reads and writes. You would not use BigQuery for user sessions or real-time app data. You would use it to answer questions like “how many users signed up last week?” over your historical data. Firestore can export to BigQuery automatically, so the two are often used together rather than in competition.
For a full structured decision guide, see Choosing the Right Storage Service.
Pricing: how costs add up
Firestore charges per operation, not per compute hour. Every document read, write, and delete is a billable unit. Storage is charged per GB per month, and network egress adds a small additional cost.
The daily free tier covers 50,000 reads, 20,000 writes, and 20,000 deletes plus 1 GB of storage. Small projects and prototypes typically stay within it. Production applications with active users will exceed it quickly.
Think of Firestore billing like paying per taxi ride versus a monthly car lease. With Cloud SQL, you pay for the running instance whether it is busy or idle, like a car lease. With Firestore, you pay per document touched, like a taxi fare. A quick trip is cheap. But if you ask the taxi to drive every street in the city just to find one address, you pay for every mile. That is what happens when a query scans a large collection without filters.
Reading 10,000 documents to display a paginated list of 20 items is billed as 10,000 reads. This is a common pattern in applications that scan collections without filters. The fix requires the right data model and indexes from the start. It cannot be patched at the application layer after the fact. Use indexed field filters and cursor-based pagination so each request reads only the documents it actually needs.
Common beginner mistakes
Choosing Datastore mode for a new project. Datastore mode exists purely for compatibility with older Cloud Datastore applications. There is no feature in Datastore mode that is preferable over Native mode for new work. The choice is permanent.
Designing the data model like a relational database. Normalising data into separate collections and trying to join them at query time does not work. Denormalisation — storing duplicated or pre-combined data in a single document — is not a code smell in Firestore. It is how the database is meant to be used. Read the Firestore Data Model guide before you start building, not after.
Leaving security rules in test mode for production. A new Firestore database starts in test mode, which allows any authenticated user to read and write everything. That is fine for a local prototype and a serious vulnerability in production. See Firestore Security Rules before you ship.
Running large collection scans without filters. Querying a collection without field filters returns every document and bills a read for each one. In a collection with 500,000 documents, that is a significant bill from a single request. Always add indexed filters and limit results with cursor-based pagination.
Using Firestore for workloads it was not designed for. Analytics over millions of records, high-frequency updates to shared counters, and full-text search are all outside Firestore’s design envelope. Choosing Firestore for those cases creates cost and correctness problems that cannot be fixed without switching databases.
Two things will cause you problems if you skip them: security rules and query design. A Firestore database in test mode is open to any authenticated user. And a query that scans a large collection without filters can generate a very large bill in a single request. Both need to be solved at the data model level before launch, not patched after.
Key takeaways
- Firestore is a serverless NoSQL document database: data lives in collections of documents with no fixed schema
- Documents are key-value stores (like JSON); collections group them; subcollections enable hierarchy
- Queries are index-driven. There are no joins and no ad-hoc SQL. Your data model must match your queries from the start
- Choose Native mode for all new projects. Datastore mode is for migrating Cloud Datastore applications only. The choice is permanent
- Billing is per operation (read, write, delete). Unoptimised queries that scan large collections can generate large bills quickly
- Best fit: mobile and web apps, real-time features, flexible schemas, offline-capable clients, low-overhead backends
- Poor fit: relational data with joins, complex analytics, very high single-document write rates, full-text search
Frequently asked questions
Is Firestore SQL or NoSQL?
Firestore is a NoSQL database. It stores data as documents (similar to JSON objects) grouped into collections, not in tables with rows and columns. There is no SQL query language, no schema enforcement at the database level, and no joins. If you need SQL, use Cloud SQL instead.
Is Firestore serverless?
Yes. Firestore is fully serverless. There are no instances, nodes, or VMs to provision or manage. It scales automatically with your workload. You pay only for the operations you perform (document reads, writes, deletes) and for storage, not for reserved capacity.
What is the difference between Firestore Native mode and Datastore mode?
Native mode is the current generation, recommended for all new projects. It supports real-time listeners, offline sync for mobile and web clients, and multi-document atomic transactions. Datastore mode is a legacy compatibility mode that preserves the behaviour of the older Cloud Datastore API for existing migrations. You cannot switch between modes after a database is created. Choose Native mode for anything new.
When should I use Cloud SQL instead of Firestore?
Use Cloud SQL when your data is fundamentally relational: when you need joins, foreign key constraints, transactions across multiple unrelated tables, or complex aggregation queries. Firestore cannot express arbitrary joins or filter on unanticipated fields without an index. If you are building a finance system, an ERP, or anything where relational integrity needs to be enforced at the database layer, Cloud SQL is the right tool.
Why can Firestore become unexpectedly expensive?
Firestore charges per document read. If your queries return large numbers of documents unnecessarily, for example fetching an entire collection to display a paginated result, costs escalate quickly. Every document returned counts as a billable read, regardless of whether your application uses all the data. The fix is query design: use indexed filters, pagination with cursors, and avoid scanning large collections without constraints.