Data Connect vs Firestore — which one?
Both are databases in the same Firebase project, but they solve different problems. Firestore stores documents; Data Connect stores rows in relational tables.Reach for Data Connect when…
User, Friendship, Post, Order tables joined by foreign keys. You need joins, server-side aggregation, or transactions that write several rows atomically. You want a typed query surface the compiler checks.Reach for Firestore when…
Before you start — three requirements
Data Connect asks a little more of your project than Firestore does:iOS 17 or newer
iOS 17 or newer
@Observable), which is iOS 17-only. Modaal raises your app’s deployment floor to iOS 17 automatically when it wires the SDK in. If your app must ship to iOS 16 or earlier, Data Connect isn’t an option — use Firestore.The Blaze (pay-as-you-go) plan
The Blaze (pay-as-you-go) plan
A project region — chosen once, effectively permanent
A project region — chosen once, effectively permanent
europe-west1, europe-west3, …) so the data stays in the EU. The Data Connect buttons stay disabled with a “Set the project region first” hint until you’ve chosen one.The three panel actions
Data Connect lives in the Firebase panel (the flame icon in the left sidebar). Once a region is set, three actions drive everything — and, exactly like every other Firebase operation, each one streams its logs into a modal and runs against Google’s servers for you. The agent points you at the button; it never shells out to thefirebase CLI itself.
Set up — scaffold the service
firebase/dataconnect/ — a dataconnect.yaml, an (empty, comment-only) schema/schema.gql, and a connector/ with queries.gql + mutations.gql — deriving sensible defaults from your project name (service id, Cloud SQL instance id, and the Swift package name, e.g. package MyAppConnector, service myapp).schema.gql compiles and deploys fine — it provisions the service and the Cloud SQL instance with no tables. Add tables when you’re ready; there’s no “you must define something first” step.Generate SDK — produce the typed Swift package
src-ios/Libraries/<Package>/, and auto-wires it into your app’s main Swift package (raising the iOS-17 floor). You don’t touch Package.swift or xcodegen.yml — the panel does it.Deploy — push the schema live
What Modaal puts in your project
How the agent builds with it
You don’t write GraphQL or wire up Swift generics by hand. Ask the agent, and it reads Modaal’s Data Connect knowledge base and does the modeling for you:“Model a friends feature in Data Connect: aThe agent will:Usertable keyed by the Firebase Auth uid, aFriendshipjoin table with anisActiveflag, and aMemorytable each user can share with several friends. Add queries for my friends list and my incoming feed.”
- Write the tables and relationships in
schema/schema.gql, and the read/write operations inqueries.gql/mutations.gql. - Tell you to click Regenerate SDK and Deploy in the panel (only you can push to Google).
- Write the iOS data layer behind a per-feature repository protocol — one clean protocol your screens depend on, with the generated SDK hidden inside a single implementation file. That keeps your views testable (they inject a fake repository) and swappable (Data Connect could be replaced without touching feature code).
- Keep server-only operations (privileged cross-user reads, account-deletion cascades, invite redemption) out of the shipped client SDK by putting them in a separate connector, so they never appear as callable symbols in your app binary.
Keep the UI in sync with live queries
Data Connect queries can be observed — the UI updates when the underlying rows change — the same way Firestore listeners work. The agent bridges the generated observable query into your app’s Combine or SwiftUI layer and cleans up the subscription when the view goes away. Refreshes can be automatic (a query keyed by primary key refreshes when a matching write executes) or time-based (a periodic backstop that catches changes made on another device). You don’t manage any of this directly — you ask for “a friends list that stays in sync across devices” and the agent picks the right refresh strategy.Deploying schema changes
Deploying Data Connect is different from deploying rules or functions, because the database has data in it. Two kinds of migration:- Additive — a new table, a new nullable column, a new index. These apply automatically, no prompt.
- Destructive — dropping a column, narrowing a type, removing a
NOT NULLconstraint. These are blocked: the deploy stops, the modal shows you the Postgres migration plan (the exact SQL), and an explicit Apply destructive migration button is the only way to proceed.
A deploy failed with "An Internal error has occurred. Please try again." — should I retry?
A deploy failed with "An Internal error has occurred. Please try again." — should I retry?
ensuring required API … sqladmin.googleapis.com lines, it’s usually not a flaky backend — it’s a breaking change (a destructive SQL migration, or a query field that changed from required to optional) that the non-interactive deploy can’t prompt you to confirm. Retrying the same deploy just loops.Modaal detects this and surfaces a Data Connect deploy blocked gate with two ways forward: Deploy with --force (after you’ve read the diff in the log), or Open in Terminal (you run the deploy yourself and answer the breaking-change prompt interactively). When in doubt, use Open in Terminal so you can review it live.Using both together
Data Connect and Firestore coexist in one app with no special wiring — Modaal’s Firebase SDK resolves to a single shared Firebase core, which the generated Data Connect package uses too. A common split:- Firestore — user profile documents, settings, chat messages, anything document-shaped or offline-first.
- Data Connect — the relational core (posts ↔ authors ↔ tags, friendships, orders ↔ items), anything that benefits from joins or transactional consistency.
Fix greyed-out buttons, stale SDKs and blocked deploys
The app crashes decoding a Data Connect response after a schema change
The app crashes decoding a Data Connect response after a schema change
.gql edit.Build error: cannot find type 'Observable' in scope
Build error: cannot find type 'Observable' in scope
Deploy fails mentioning the Blaze plan or billing
Deploy fails mentioning the Blaze plan or billing
I opened a project that already had a firebase/dataconnect/ folder
I opened a project that already had a firebase/dataconnect/ folder
Something else is off with Firebase generally
Something else is off with Firebase generally