Cloud SQL vs Firestore in GCP: Which Database Should You Choose?
Cloud SQL and Firestore solve different problems. Cloud SQL gives you a traditional relational database with SQL queries, joins, and strict schemas. Firestore gives you a serverless document database with real-time sync, flexible schemas, and automatic scaling. Many applications use both. Cloud SQL handles the structured transactional data while Firestore powers the user-facing real-time features.
Quick answer
- Choose Cloud SQL if your data is relational (users, orders, products), you need joins or complex queries, or your app uses an ORM like Django, Rails, or Hibernate.
- Choose Firestore if you need real-time sync to mobile or web clients, flexible document schemas, automatic scaling with zero ops, or offline-first mobile support.
- Use both when your app has relational back-end data (billing, inventory) and user-facing real-time features (chat, notifications, activity feeds).
- Cost shape: Firestore starts free and charges per operation. Cloud SQL has a minimum monthly cost but is cheaper per query at high volume.
- Still unsure? If you would describe your data as “tables with relationships,” start with Cloud SQL. If you would describe it as “documents that clients read in real time,” start with Firestore.
Simple explanation
Cloud SQL is a spreadsheet with strict rules. Every row must have the same columns. You define the structure upfront: a “users” table always has name, email, and created_at. The power is that you can ask questions across tables. “Show me all orders from users who signed up last month.” That cross-table question is called a join, and it is what relational databases do best.
Firestore is a filing cabinet full of folders. Each folder (called a collection) holds documents, and each document can have whatever fields it needs. One user document might have a phone number while another does not. That is perfectly fine. The power is that Firestore pushes changes to your app in real time. When one user updates their profile, every device showing that profile sees the change instantly.
The key trade-off: Cloud SQL gives you powerful querying across structured data. Firestore gives you real-time sync and effortless scaling. You give up joins and complex queries in Firestore. You give up real-time push and automatic horizontal scaling in Cloud SQL.
How each one works
Cloud SQL
Cloud SQL runs a fully managed MySQL, PostgreSQL, or SQL Server instance on a virtual machine you choose. You pick the CPU, memory, and storage. Google handles patching, replication, backups, and failover. Your application connects to Cloud SQL using standard database drivers, just like it would connect to any MySQL or PostgreSQL server.
Data lives in tables with defined columns and types. You write SQL to insert, update, query, and delete data. Connections are secured through Cloud SQL connectors, the Auth Proxy, or private IP networking depending on where your application runs. For Cloud Run, the built-in Cloud SQL connector is the simplest path. For GKE, the Cloud SQL Auth Proxy sidecar or private IP works well. For external apps, the Auth Proxy handles IAM authentication and encryption.
Cloud SQL scales vertically. You resize the instance when you need more capacity. Read replicas add read throughput. Write throughput is limited to the primary instance, which is sufficient for the vast majority of web applications.
Firestore
Firestore is serverless. There is no instance to provision. You create a database, define security rules, and start reading and writing documents. Google handles all infrastructure, scaling, and replication behind the scenes.
Data is organised into collections and documents. A “users” collection contains user documents, each identified by a unique ID. Documents hold fields (strings, numbers, arrays, nested objects) and can have subcollections for hierarchical data. The data model is flexible. Documents in the same collection do not need identical fields.
Queries in Firestore work differently from SQL. You query a single collection (or collection group) by filtering on indexed fields. Firestore requires an index for every query pattern, and composite indexes must be created explicitly. There are no joins. If you need data from two collections, you make two queries. This constraint is deliberate: it guarantees that every query scales linearly with the result set size, not the total database size.
Firestore’s “no joins” rule is not a limitation they forgot to fix. It is a design choice. By only allowing queries against a single collection, Firestore guarantees that query speed depends on the number of results, not the total size of your database. A collection with ten billion documents returns a ten-result query just as fast as a collection with ten thousand. That guarantee is what makes automatic horizontal scaling possible.
Use Firestore in Native mode for all new projects. Native mode provides real-time listeners, offline support, and stronger consistency guarantees than the older Datastore mode.
Side-by-side comparison
| Dimension | Cloud SQL | Firestore |
|---|---|---|
| Data model | Relational (tables, rows, columns) | Document (collections, documents, fields) |
| Schema | Fixed (defined upfront, enforced) | Flexible (per document, no enforcement) |
| Query language | Full SQL | Firestore query API (field filters, ordering, limits) |
| Joins | Yes (multi-table joins) | No (multiple queries required) |
| Aggregations | Full (SUM, COUNT, AVG, GROUP BY, window functions) | count(), sum(), average() natively; complex aggregations require application code or export to BigQuery |
| Transactions | Full ACID across tables | ACID within a transaction (up to 500 documents) |
| Scaling model | Vertical (instance resize) + read replicas | Horizontal (automatic, serverless) |
| Write scaling | Single primary instance | Distributed (scales with traffic) |
| Operations burden | Instance sizing, patching, backups, connection management | Near zero (serverless) |
| Pricing model | Per instance hour + storage | Per read/write/delete operation + storage |
| Minimum monthly cost | ~$7–$15 (smallest production instance) | $0 (free tier covers low usage) |
| Real-time sync | No native support | Yes (real-time listeners push changes to clients) |
| Offline support | No | Yes (Firebase SDKs cache data locally) |
| Security model | IAM, database users, Cloud SQL connectors/Auth Proxy, private IP | IAM, Firestore Security Rules (per-document, per-field) |
| Reporting suitability | Strong (SQL, joins, aggregations) | Limited (export to BigQuery for complex reporting) |
| Regions | Single region (HA within region, cross-region read replicas) | Single region or multi-region |
| Best-fit workloads | Transactional apps, ORM-backed APIs, reporting | Real-time apps, mobile-first, content feeds, IoT |
When to use Cloud SQL
Cloud SQL is the right choice when your data is fundamentally relational and your queries need to cross entity boundaries.
- Relational data with joins. Users, orders, products, invoices, and line items. Data with foreign key relationships you need to query across. A query like “total revenue by product category for customers in a specific region” requires joins and aggregations that only SQL handles well.
- Complex reporting and analytics. Dashboards, admin panels, and internal tools that run aggregations, window functions, CTEs, and subqueries. For heavier analytical workloads, consider pairing Cloud SQL with BigQuery.
- ORM-backed applications. Frameworks like Django, Rails, Laravel, and Spring expect a relational database. Cloud SQL with PostgreSQL or MySQL works out of the box.
- Strict schema enforcement. When every record must conform to a defined structure. Think financial transactions, compliance data, and inventory systems.
- Migrating existing SQL databases. If your application already uses MySQL or PostgreSQL, Cloud SQL is the lowest-friction path to a managed GCP database.
- Multi-table transactions. Operations that must atomically update multiple tables. Transferring funds between accounts, or processing an order that updates inventory and creates a shipment record.
When to use Firestore
Firestore is the right choice when your data is document-shaped, your access patterns are simple, and you benefit from real-time sync or automatic scaling.
- Real-time applications. Chat, collaboration tools, live dashboards, and multiplayer game state. Any feature where changes must push to connected clients instantly without polling.
- Mobile and web apps with offline support. The Firebase SDK caches data locally. Users can read and write while offline, and changes sync automatically when connectivity returns.
- Flexible or evolving schemas. User profiles, feature flags, content documents, and configuration objects. Data where different records legitimately have different fields.
- Globally distributed users. Firestore multi-region deployments give low-latency reads from any region. For apps with users on every continent, this matters.
- Serverless and zero-ops preference. No instance sizing, no connection pool management, no patching. Firestore scales automatically from zero to millions of operations per second.
- Bursty or unpredictable traffic. A viral moment or seasonal spike does not require pre-provisioning. Firestore absorbs traffic automatically.
When to use both together
Many production applications use Cloud SQL and Firestore side by side, each handling what it does best. This is not over-engineering. It is using the right tool for each data type.
The common pattern: Cloud SQL stores your core transactional data (orders, inventory, billing, user accounts with relational integrity). Firestore stores user-facing real-time data (chat messages, notifications, activity feeds, presence indicators). Both databases are accessible from the same Cloud Run service or GKE pod.
Cloud SQL is the back office. It handles the structured records that power your business logic: orders, payments, inventory. Firestore is the front stage. It handles the live data that your users see and interact with in real time: chat threads, notifications, activity feeds. Each database stays in its lane, and your application talks to both.
Example architecture: e-commerce with live chat
- Cloud SQL (PostgreSQL) holds the product catalogue, orders, inventory counts, and payment records. Admin dashboards query Cloud SQL for revenue reports and inventory alerts.
- Firestore holds customer support chat threads, order status updates pushed to the buyer in real time, and user notification preferences. The mobile app uses Firestore listeners to show live order tracking.
- A Cloud Run service sits in front of both. Write endpoints hit Cloud SQL for order operations. The chat service reads and writes Firestore directly from the client using security rules, with server-side validation through Cloud Functions when needed.
Example architecture: SaaS with real-time collaboration
- Cloud SQL stores tenant data, subscription billing, audit logs, and role-based access control.
- Firestore stores the real-time collaboration state: document edits, cursor positions, comments, and presence indicators. Each user’s client subscribes to Firestore listeners for instant updates.
The key is that each database handles the access pattern it was built for. Do not force relational queries into Firestore, and do not build a polling system in Cloud SQL when Firestore gives you real-time push natively.
How to choose for common app types
- E-commerce (orders, inventory, checkout): Cloud SQL. Orders and inventory are deeply relational. You need joins for reports and ACID transactions for checkout. Add Firestore only if you need real-time features like live order tracking pushed to mobile clients.
- SaaS with admin dashboard: Cloud SQL for the core data model. Dashboards need joins and aggregations that Firestore cannot provide. Consider Firestore for any real-time collaboration features within the app.
- Chat or collaboration app: Firestore. Chat messages, typing indicators, and presence are document-shaped and benefit enormously from real-time listeners and offline support. Use Cloud SQL only if you need relational user management or analytics.
- Mobile app with offline-first sync: Firestore. The Firebase SDK handles offline caching, conflict resolution, and background sync. Cloud SQL has no built-in offline story for mobile clients.
- CMS or content feed: Either can work. Firestore is a natural fit for flexible content documents with varying fields. Cloud SQL works better if content has complex relationships (tags, categories, authors) you need to query across.
- Reporting-heavy back office: Cloud SQL. Ad-hoc queries, joins, and aggregations are essential for internal tools. For large-scale analytics, pair Cloud SQL with BigQuery.
- IoT data ingestion: Firestore handles high-throughput writes from many devices without provisioning. If you need to run analytical queries over the ingested data, stream it from Firestore to BigQuery.
Every recommendation above is a starting point, not a rule. Plenty of successful SaaS apps run entirely on Firestore, and plenty of mobile apps use Cloud SQL behind an API. The question is whether your primary access pattern is relational queries or document lookups. Start with whichever matches your core use case and add the second database only when a clear need appears.
Common mistakes
- Treating Firestore like a relational database. Creating collections that mirror SQL tables and then making multiple queries to “join” them manually leads to slow, expensive reads. If your data is relational, use Cloud SQL. If you choose Firestore, denormalise deliberately. Store the data you need in each document to avoid multi-read joins.
- Forgetting composite indexes in Firestore. Firestore requires a composite index for any query that filters or orders on multiple fields. Without the index, the query fails. Create indexes using the Firebase CLI or console before deploying queries to production. The error message includes a direct link to create the missing index.
- Under-sizing Cloud SQL for production. The smallest Cloud SQL instances (db-f1-micro) are designed for development and testing, not production workloads. They have strict connection limits and limited CPU. Start with at least a lightweight general-purpose instance and monitor CPU, memory, and connection counts. See Cloud SQL cost optimisation for right-sizing guidance.
- Assuming Firestore is free at scale. Firestore bills per operation. An app reading 10,000 documents per second accumulates costs quickly. Estimate your read and write volumes before committing. Design your data model to minimise reads per user action. One document read is cheaper than ten.
- Using a single connection approach for all environments. Cloud SQL offers multiple connection methods: built-in connectors for Cloud Run and App Engine, the Auth Proxy sidecar for GKE and Compute Engine, and private IP for VPC-native workloads. Choose the method that matches your runtime environment rather than defaulting to one approach everywhere.
Cloud SQL vs Firestore for cost
The pricing models are fundamentally different, and which is cheaper depends entirely on your traffic pattern.
Cloud SQL charges for the instance (CPU + memory per hour), storage, and network egress. You pay for the instance whether it is handling one query or one thousand per second. The smallest production-viable instances start around $7–15 per month. A mid-range instance with 2 vCPUs and 8 GB RAM runs roughly $50–100 per month depending on region and database engine. The upside: once you are paying for the instance, additional queries within its capacity cost nothing extra.
Firestore charges per document read ($0.036 per 100K reads), per write ($0.108 per 100K writes), per delete ($0.012 per 100K deletes), plus storage ($0.108 per GB/month in regional, more for multi-region). There is no instance to pay for. The free tier covers 50K reads, 20K writes, and 20K deletes per day, which is enough for development and low-traffic apps. At high traffic, costs scale linearly with operations.
Firestore is cheaper for low-traffic applications and prototypes. Cloud SQL is typically cheaper for sustained high-traffic applications where you would be paying for millions of Firestore operations daily. The crossover point depends on your read/write ratio and document sizes. Run the numbers for your expected traffic rather than assuming one is always cheaper.
For a detailed breakdown of Cloud SQL pricing strategies, see Cloud SQL cost optimisation.
Frequently asked questions
What is the main difference between Cloud SQL and Firestore?
Cloud SQL is a managed relational database (MySQL, PostgreSQL, or SQL Server) that stores data in tables with a fixed schema. It supports SQL queries, joins, and full ACID transactions. Firestore is a serverless NoSQL document database that stores flexible JSON-like documents in collections. Cloud SQL is best for structured relational data with complex queries. Firestore is best for document-oriented data with real-time sync and automatic scaling.
Can I use Firestore instead of a relational database?
For some applications, yes. Firestore works well for user profiles, content feeds, chat messages, mobile app data, and configuration stores. It does not support joins or ad-hoc SQL queries. If your application needs multi-table joins, complex aggregations beyond count/sum/average, or flexible reporting queries, Cloud SQL is the better choice.
Which is cheaper, Cloud SQL or Firestore?
It depends on traffic. Firestore has no minimum cost and bills per operation, making it effectively free at low traffic. Cloud SQL has a minimum instance cost starting around $7 to $15 per month even when idle. At high traffic with thousands of document reads per second, Firestore per-operation costs can exceed Cloud SQL instance costs. Estimate your read and write volumes before choosing.
Can I use both Cloud SQL and Firestore in the same application?
Yes, and many production applications do. A common pattern is using Cloud SQL for transactional relational data like orders, inventory, and billing, while using Firestore for user-facing real-time data like chat messages, notifications, or activity feeds. Cloud Run and GKE can connect to both databases from the same service.
Does Firestore support aggregation queries?
Yes. Firestore natively supports count(), sum(), and average() aggregation queries that run server-side without downloading documents. For more complex aggregations like GROUP BY, percentiles, or window functions, you need to compute them in application code, use Cloud Functions, or export data to BigQuery.