Firestore is a serverless NoSQL database from Google Cloud and Firebase. You store your data as small JSON-like documents, and your app can read them, query them and even get live updates the moment something changes. There is no server to install, no disk to resize and no replication to set up.
If you have only worked with SQL databases so far, Firestore will feel different at first. In this guide I will explain it the way I wish someone had explained it to me: by comparing it with SQL, then building a real order-tracking example step by step.
Last reviewed: November 2026
In this guide:
- What is Firestore?
- How Firestore stores data (SQL vs Firestore)
- Why use Firestore?
- Where to use Firestore (and where not to)
- Firestore vs Cloud SQL vs BigQuery
- How to use Firestore step by step
- Real-time example: live order tracking
- Security rules
- Firestore pricing and free tier
- FAQs
What Is Firestore?
Google Cloud Firestore (also called Cloud Firestore) is a fully managed, document-based NoSQL database. Google runs it for you, copies your data across machines, and scales it automatically as your app grows.
Three things make Firestore special:
- Real-time updates: Your app can “listen” to a document. When the data changes, the new value reaches the app in about a second, without refreshing.
- Offline support: On Android, iOS and web, the Firebase SDK keeps a local copy. The app keeps working without internet and syncs when the connection comes back.
- Direct access from mobile apps: With security rules, a mobile or web app can talk to Firestore directly. For many apps you do not need to build a backend API at all.
Simple way to remember it: A SQL database is like a well-organised register with fixed columns. Firestore is like a cupboard of labelled folders, where each folder holds its own sheet of information, and every person watching the cupboard is told the moment a sheet changes.
Firestore Editions and Modes
When you create a database, Google Cloud asks you to choose an edition and a mode. Here is what they mean in plain words:
| Option | What it means | Who should pick it |
|---|---|---|
| Standard edition | Core Firestore features, billed per document read and written | Most beginners and mobile apps |
| Enterprise edition | Advanced query engine, MongoDB-compatible API, billed by data size | Large apps or teams moving from MongoDB |
| Native mode | Full Firestore API with real-time listeners and offline support | All new apps |
| Datastore mode | Older Datastore API, no real-time listeners | Old App Engine / Datastore projects |
For this tutorial, choose Standard edition and Native mode. The mode cannot be changed later, so pick carefully.
How Firestore Stores Data (SQL vs Firestore)
Firestore has only three building blocks:
- Collection: A group of documents, for example
ordersorusers. - Document: One record inside a collection, with a unique ID such as
A1001. - Field: A key-value pair inside a document, such as
status: "Packed".
If you know SQL, this table makes it easy:
| SQL database | Firestore |
|---|---|
| Table | Collection |
| Row | Document |
| Column | Field |
| Primary key | Document ID |
| Fixed schema | Flexible: each document can have different fields |
| JOIN between tables | No JOINs: store related data together or use subcollections |
| SELECT … WHERE | Queries with where, orderBy and limit |
Here is what one order document looks like inside the orders collection:
orders (collection)
└── A1001 (document)
├── customer: "Rahul Sharma"
├── item: "Wireless Mouse"
├── price: 799
├── status: "Packed"
├── address: { city: "Bhopal", pincode: "462001" }
└── tracking (subcollection)
└── step1 (document) → { message: "Order packed", time: ... }
Notice two things. First, address is a map (a small object) stored inside the document, so you get it without a JOIN. Second, tracking is a subcollection, a collection that lives under one document. Use subcollections for lists that can grow large, like order history or chat messages.
If you come from a normalized SQL design, this is the biggest mindset change: in Firestore, you design data around the screens your app shows, not around avoiding duplicate data.
Why Use Firestore?
- No servers to manage: No installation, patching, backups setup or disk resizing.
- Live data out of the box: Chat messages, order status and scores update on every screen instantly.
- Works offline: Users in low-network areas can keep using the app.
- Scales automatically: The same database works for 10 users and for millions.
- Free daily quota: Small apps and side projects can often run at zero cost.
- Flexible schema: Add a new field tomorrow without an
ALTER TABLE. - Fits the Google ecosystem: Works with Firebase Authentication, Cloud Functions, Cloud Run and BigQuery.
Where to Use Firestore (and Where Not To)
Firestore is a great fit for:
| Use case | Why Firestore works well |
|---|---|
| Chat and messaging apps | New messages appear instantly with real-time listeners |
| Food delivery or e-commerce order tracking | Status changes reach the customer’s phone immediately |
| User profiles and app settings | Each user gets one document, read quickly by ID |
| Matrimonial, dating and social apps | Profiles, likes, matches and notifications with flexible fields |
| Live dashboards and leaderboards | Scores and counters update on every screen |
| Offline-first field apps | Sales or survey apps work without network and sync later |
Choose something else when:
- You need complex JOINs, strict foreign keys or heavy multi-table transactions, like an accounting system. Use Cloud SQL or another RDBMS.
- You need analytics on millions of rows, like monthly sales reports. Use BigQuery.
- You need full-text search like “find products matching blue cotton shirt“. Standard edition does not support this, so pair it with a search service.
- You store large files such as images or videos. Put the files in Cloud Storage and keep only their URL in Firestore.
Firestore vs Cloud SQL vs BigQuery
| Point | Firestore | Cloud SQL | BigQuery |
|---|---|---|---|
| Type | NoSQL document database | Relational (MySQL, PostgreSQL, SQL Server) | Data warehouse |
| Best for | Mobile and web app data | Business apps with relations | Analytics and reports |
| Real-time listeners | Yes | No | No |
| JOINs | No | Yes | Yes |
| Server management | None | You choose instance size | None |
| Billing model | Per read, write and storage | Per instance running time | Per data scanned and storage |
A very common real-world setup uses all three: Firestore for the app, Cloud SQL for billing, and BigQuery for reports.
How to Use Firestore Step by Step
Step 1: Create a Firestore Database
- Open the Firestore page in the Google Cloud console and select your project.
- Click Create a Firestore database.
- Keep the database ID as
(default). Only this first database gets the free quota. - Choose Standard edition and Firestore Native mode.
- Choose a location. For users in India, pick
asia-south1(Mumbai). The location cannot be changed later. - Select Production rules (secure by default) and click Create.
You can also create it from the command line:
gcloud services enable firestore.googleapis.com
gcloud firestore databases create --location=asia-south1
If you are building a mobile app, you can do the same from the Firebase console under Build → Firestore Database. Firebase and Google Cloud share the same database.
Step 2: Set Up Python on Your Computer
Install the client library and sign in so your code can reach your project:
pip install google-cloud-firestore
gcloud auth application-default login
gcloud config set project PROJECT_ID
Replace PROJECT_ID with your own project ID. On Cloud Run or a VM, you do not need to sign in like this. The code uses the attached service account, which needs the Cloud Datastore User role. Read our IAM guide if roles are new to you.
Step 3: Add, Read, Update and Delete Data
Create a file named orders_crud.py. It covers all four CRUD operations:
from google.cloud import firestore
from google.cloud.firestore_v1.base_query import FieldFilter
db = firestore.Client()
orders = db.collection("orders")
# 1. CREATE: add two orders with our own IDs
orders.document("A1001").set({
"userId": "user_rahul",
"customer": "Rahul Sharma",
"item": "Wireless Mouse",
"price": 799,
"status": "Placed",
"createdAt": firestore.SERVER_TIMESTAMP,
})
orders.document("A1002").set({
"userId": "user_priya",
"customer": "Priya Verma",
"item": "Laptop Bag",
"price": 1499,
"status": "Shipped",
"createdAt": firestore.SERVER_TIMESTAMP,
})
print("Orders created")
# 2. READ: get one order by ID
doc = orders.document("A1001").get()
if doc.exists:
print("Order A1001:", doc.to_dict())
# 3. QUERY: find all shipped orders (like SELECT ... WHERE)
shipped = orders.where(filter=FieldFilter("status", "==", "Shipped")).stream()
for order in shipped:
print("Shipped:", order.id, order.to_dict()["item"])
# 4. UPDATE: change only the status field
orders.document("A1001").update({"status": "Packed"})
print("A1001 updated to Packed")
# 5. DELETE: remove an order (uncomment to try)
# orders.document("A1002").delete()
Run it:
python orders_crud.py
Open the Firestore page in the console and you will see the orders collection with both documents. Note that Firestore created the collection automatically when you wrote the first document. There is no CREATE TABLE step.
Quick SQL comparison:
| SQL | Firestore (Python) |
|---|---|
INSERT INTO orders ... | orders.document("A1001").set({...}) |
SELECT * FROM orders WHERE id = 'A1001' | orders.document("A1001").get() |
SELECT * FROM orders WHERE status = 'Shipped' | orders.where(filter=FieldFilter("status", "==", "Shipped")) |
UPDATE orders SET status = 'Packed' ... | orders.document("A1001").update({"status": "Packed"}) |
DELETE FROM orders WHERE id = 'A1002' | orders.document("A1002").delete() |
Real-Time Example: Live Order Tracking
Problem: A customer in Bhopal orders a wireless mouse. They keep opening the app to check “Has it shipped yet?” With a normal SQL backend, the app must ask the server again and again (polling). That wastes battery, data and server money.
Solution with Firestore: The app listens to the order document. When the warehouse changes the status, Firestore pushes the new value to the customer’s screen automatically.
Part 1: The Customer Side (Listener)
Create track_order.py. This plays the role of the customer’s app:
import time
from google.cloud import firestore
db = firestore.Client()
def on_order_change(doc_snapshots, changes, read_time):
for doc in doc_snapshots:
data = doc.to_dict() or {}
print(f"Order {doc.id} is now: {data.get('status')}")
watch = db.collection("orders").document("A1001").on_snapshot(on_order_change)
print("Listening for changes to order A1001. Press Ctrl+C to stop.")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
watch.unsubscribe()
print("Stopped listening.")
Part 2: The Warehouse Side (Updater)
Create update_status.py. This plays the role of the warehouse staff app:
import time
from google.cloud import firestore
db = firestore.Client()
order_ref = db.collection("orders").document("A1001")
for status in ["Packed", "Shipped", "Out for Delivery", "Delivered"]:
order_ref.update({"status": status, "updatedAt": firestore.SERVER_TIMESTAMP})
print("Warehouse set status to:", status)
time.sleep(5)
Part 3: Watch It Work
Open two terminal windows. Run the listener in the first one:
python track_order.py
Then run the updater in the second one:
python update_status.py
Every five seconds the first window prints the new status on its own, without asking:
Order A1001 is now: Packed
Order A1001 is now: Shipped
Order A1001 is now: Out for Delivery
Order A1001 is now: Delivered
This is exactly how food delivery and courier apps show live status. You can also change the status field by hand in the console and watch the listener react.
Part 4: The Same Listener in an Android App (Kotlin)
In a real app, the listener lives in the customer’s phone. First, connect your app to Firebase (add google-services.json) and add Firestore to app/build.gradle.kts. Replace LATEST_VERSION with the current Firebase BoM version from the Firebase release notes:
dependencies {
implementation(platform("com.google.firebase:firebase-bom:LATEST_VERSION"))
implementation("com.google.firebase:firebase-firestore")
}
Then listen to the order in your Activity or Fragment:
import com.google.firebase.Firebase
import com.google.firebase.firestore.ListenerRegistration
import com.google.firebase.firestore.firestore
private var orderListener: ListenerRegistration? = null
private fun trackOrder(orderId: String) {
val db = Firebase.firestore
orderListener = db.collection("orders").document(orderId)
.addSnapshotListener { snapshot, error ->
if (error != null) {
statusText.text = "Could not load order"
return@addSnapshotListener
}
val status = snapshot?.getString("status") ?: "Unknown"
statusText.text = "Order status: $status"
}
}
override fun onStop() {
super.onStop()
orderListener?.remove() // stop listening to save reads and battery
}
Always remove listeners when the screen closes. An open listener keeps counting reads every time the document changes.
Firestore Security Rules
When a mobile app talks to Firestore directly, security rules decide who can read or write each document. Server code that uses a service account (like our Python scripts) is controlled by IAM instead and skips these rules.
For our order app, a customer should see only their own orders, and only the backend should change them. Go to Firestore → Rules and paste this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /orders/{orderId} {
// A signed-in customer can read only their own orders
allow read: if request.auth != null
&& request.auth.uid == resource.data.userId;
// Only the backend (service account) can create or change orders
allow write: if false;
}
}
}
This uses Firebase Authentication. The userId field in each order must match the signed-in user’s UID. Never publish an app with test-mode rules like allow read, write: if true;. Anyone could read or delete your whole database. For an extra layer that blocks scripts and bots, add Firebase App Check.
Firestore Pricing and Free Tier
With Standard edition, you pay for documents read, written and deleted, the data you store, and outbound network traffic. The (default) database in each project gets a free daily quota:
| Item | Free quota | Price after free quota (us-central1) |
|---|---|---|
| Document reads | 50,000 per day | $0.03 per 100,000 |
| Document writes | 20,000 per day | $0.09 per 100,000 |
| Document deletes | 20,000 per day | $0.01 per 100,000 |
| Stored data | 1 GiB | Charged per GiB stored |
| Outbound data transfer | 10 GiB per month | Charged per GiB |
Prices differ slightly by region, including Mumbai, and the free quota resets daily around midnight Pacific time. Check the official Firestore pricing page before planning a budget.
Simple example: Your app has 1,000 daily users. Each user opens 3 screens that read 10 documents each, and places 2 orders a day.
- Reads: 1,000 × 30 = 30,000 per day. Within the 50,000 free reads.
- Writes: 1,000 × 2 = 2,000 per day. Within the 20,000 free writes.
- Cost: $0 for operations, as long as storage stays under 1 GiB.
Tips to keep reads low:
- Always use
limit()on lists, for example show the latest 20 orders, not all of them. - Remove listeners when a screen closes.
- Store totals (like an order count) in one document instead of counting thousands of documents each time.
- Set a billing budget alert in Google Cloud so a coding mistake never surprises you.
Important Firestore Limits
| Limit | Value |
|---|---|
| Maximum size of one document | 1 MiB (Standard edition) |
| Sustained writes to a single document | About 1 per second (best practice) |
| Databases per project | 100 (only one gets the free quota) |
| Database location | Cannot be changed after creation |
Common Firestore Mistakes to Avoid
- Designing like SQL: Splitting data into many collections and “joining” them in code costs extra reads. Keep data that is shown together in one document.
- Leaving test-mode rules on: Your data becomes public. Lock rules down before launch.
- Growing arrays forever: A document with a huge array of messages will hit the 1 MiB limit. Use a subcollection instead.
- Ignoring index errors: Queries that filter on several fields need a composite index. The error message contains a link that creates it for you, so just click it.
- Storing images in documents: Upload files to Cloud Storage and save only the URL.
- Picking the wrong location: Choose a region near your users, because you cannot move the database later.
How to Delete the Test Data
To remove the sample orders, run this short script:
from google.cloud import firestore
db = firestore.Client()
for doc in db.collection("orders").stream():
doc.reference.delete()
print("All test orders deleted")
Conclusion
Firestore is the easiest way to give a mobile or web app a database that scales, works offline and updates in real time, without managing a single server. Think of it as collections of documents, design your data around your app screens, and protect it with security rules.
Start with the live order-tracking example in a test project. Then deploy your Python code on Cloud Run, or connect the Kotlin listener to your own Android app. For deeper details, read the official Firestore documentation.
FAQs
Q1: Is Firestore free?
Each project gets a free daily quota on its default database: 50,000 reads, 20,000 writes, 20,000 deletes and 1 GiB of storage. Many small apps stay within it. Usage above that is charged.
Q2: Is Firestore SQL or NoSQL?
Firestore is a NoSQL document database. It stores data as documents inside collections, not as rows in tables, and it does not support SQL JOINs.
Q3: What is the difference between Firestore and Firebase Realtime Database?
Both offer real-time updates. Firestore has better querying, a clearer collection-and-document structure and automatic scaling, so Google recommends it for most new apps. Realtime Database stores everything as one large JSON tree.
Q4: Is Firestore part of Firebase or Google Cloud?
Both. It is the same database. Mobile developers usually manage it from the Firebase console, and backend developers from the Google Cloud console.
Q5: Can I use Firestore without Firebase?
Yes. Server code in Python, Java, Node.js, Go and other languages can use the Google Cloud client libraries, as shown in this tutorial.
Q6: Can I move Firestore data to BigQuery?
Yes. You can export Firestore data and load it into BigQuery, or use the Firebase extension that streams changes to BigQuery for reporting.