Transactions Updates for Data Connect in Firebase: Web Architecture & Implementation Guide
For years, choosing Firebase meant trading away relational SQL joins, strict foreign keys, and pgvector similarity search in favor of NoSQL document denormalization. Following the announcement of Transactions Updates for Data Connect by Andrea Wu on the Official Firebase Blog (2025-06-05), here is our hands-on CodingCat.dev breakdown of what actually shipped, how it works under the hood, and how we wire it into production TypeScript, Next.js, Astro, SvelteKit, React, and Angular applications. Note: Firebase Data Connect has been renamed to SQL Connect. Learn more in the SQL Connect announcement.
The Mental Model: Why Transactions Updates for Data Connect Matters for Web Devs
As a Google Developer Expert (GDE) for Firebase and Senior Solutions Engineer at CodingCat.dev, I evaluate every Firebase update through one lens: does it reduce boilerplate while keeping our runtime security and cloud bills predictable? Firebase Data Connect bridges that gap by pairing a managed Google Cloud SQL for PostgreSQL instance with a declarative GraphQL schema compiler that automatically generates type-safe TypeScript, React, and Angular SDKs alongside server-enforced @auth directives.
AJ Pro-Tip from Alex: Keep your authorization logic inside your Data Connect GraphQL operations using @auth(level: USER) and server-evaluated expressions like auth.uid and request.time rather than trusting client-supplied user IDs in query variables.
How It Works: Technical Breakdown & Implementation
When using a database, you may need to run multiple operations (adding, updating, and/or deleting data) successfully - or none at all. Data Connect already supported transactions, and The Firebase team announced additional support for transactions where now, you can use queried data output from a previous step within a transaction. In other words, you can do the following within a transaction:
For this blog post, let’s say you’re creating a banking app and need to create a transaction log. The transaction log shows the bank account that money was taken from and put into, the amount transferred, and the running balance for both accounts after the transaction. The schema looks like this:
type
id:
balance:
}
type
id:
to:
balanceTo:
from:
balanceFrom:
amount:
timestamp:
}Previously
You could execute a transaction on mutations by using the @transaction directive. These mutations are guaranteed to either fully succeed or fully fail, and if any of the fields within the transaction fails, the entire transaction is rolled back. From a client standpoint, any transaction failure behaves as if all fields had failed with a request error.
With the banking example, the app needs to ensure that the amount of money in one account decreases while the other increases in exactly the same (absolute) amount - and they can only both succeed. If either one fails, both fail. To do so, use a transaction where a) money gets taken out of one account and b) money gets put into another account. In the same transaction, we also need to query the balance of both accounts so you can log them later.
mutation
$from:
$to:
$amount:
)
# Step 1: take money out from $from account
takeMoney
data: {
balance_update
}
)
# Step 2: add money to $to account
addMoney
data: {
balance_update
}
)
# Step 3: get balance for $to account
balanceTo
bankAccount(id: $to) { balance }
}
# Step 4: get balance for $from account
balanceFrom
bankAccount(id: $from) { balance }
}
}Once the entire transaction begins, it will only succeed if all steps complete successfully. Otherwise, it will fail and return execution errors.
Now that we have transferred money between the accounts, the app needs to create the transaction log. To do so, we’ll have to use the balanceTo and balanceFrom from the first mutation, which we have to get from client-side code:
export
balanceFrom
)
try
const
const
const
// use balanceFrom and balanceTo
}
console.
}
};With the balance of both both accounts, You can add an entry for logging purposes:
mutation
$to:
$balanceTo:
$from:
$balanceFrom:
$amount:
bankingTransaction_insert(data: {
to
balanceTo
from
balanceFrom
amount
timestamp_expr
}
)
}New Updates
Taking a look at the example above: what if instead of needing to get the balances from two queries in the client code then passing it into another mutation, you can get the balances and directly use them to insert for the transactions log in the same transaction?
You can now do so, thanks to the new Data Connect updates where you can use information from one step inside a transaction in the next step.
mutation
$from:
$to:
$amount:
)
# Step 1: take money out from $from account
takeMoney
data: {
balance_update
}
)
# Step 2: add money to $to account
addMoney
data: {
balance_update
}
)
# Step 3: get balance for $to account
balanceTo
bankAccount(id: $to) { balance }
}
# Step 4: get balance for $from account
balanceFrom
bankAccount(id: $from) { balance }
}
# Step 5: add banking transaction information
bankingTransaction_insert(data: {
to
balanceTo_expr
from
balanceFrom_expr
amount
timestamp_expr
})
}Because you can now access and use data received from previous steps in the same transaction, all of this can be done with one transaction, simplifying the client-side code. This also makes the system more secure because before, the client could possibly manipulate logging information when sending both account balances back to the server.
In the example above, response is a new top-level binding in expressions that represents the partial response object, which includes all top-level mutation fields before the current one. We also support <field>_expr for most scalar types now, which can come in handy when you need a dynamic value from auth.token, a previous step, or computed.
Hide sensitive information with @redact
A potential security problem with the example before this new transactions feature is that the bank account amounts probably shouldn’t be exposed to the client - the client doesn’t need to know how much money is in either account.
To fix this problem, you can hide the information with @redact to remove it from the wire (and generated SDKs). In the example above, you can add @redact on the two query fields.
mutation
$from:
$to:
$amount:
)
# Steps 1 and 2 are the same
# Step 3: get balance for $to account
balanceTo
bankAccount(id: $to) { balance }
}
# Step 4: get balance for $from account
balanceFrom
bankAccount(id: $from) { balance }
}
# Step 5 is the same
bankingTransaction_insert(data: {
# other fields
balanceTo_expr
balanceFrom_expr
})
}Even though the id field was redacted, the fields are still available in response for step 5. In other words, you can still use fields in later steps even if you use @redact on it.
Using response in @check
There’s another way to use response: in @check(expr: "...")! Combined with query { … } operations in mutations, you can achieve a lot more without any additional client-server roundtrips, and you can use it to build even more complex server-side logic. Best of all, these can happen within the same @transaction, so you still get the atomicity guarantees as you’d expect from a relational database.
For the banking example, the app should make sure the balance of the account sending money does not go negative. You can add an @check to ensure this:
mutation
$from:
$to:
$amount:
)
# Steps 1-3 are the same
# Step 4: get balance for $from account
balanceFrom
expr:
message:
@redact
bankAccount($from) { balance }
}
# Step 5 is the same
}As a side note, @check has access to response.balanceFrom because @check always runs after the step to which it’s attached.
Production Web Architecture & Security Checklist
Whether we are deploying on Firebase App Hosting, Cloudflare Workers, or Vercel, shipping SQL features to production requires defense-in-depth across three layers:
- Enforce Firebase App Check & Attestation: Protect your web endpoints, Cloud Functions, Data Connect GraphQL resolvers, and Firebase AI Logic calls against unauthorized replay or billing abuse using Firebase App Check with reCAPTCHA Enterprise.
- Validate Locally with the Firebase Emulator Suite: Run deterministic integration tests against local Firestore, Auth, Functions, and Data Connect PostgreSQL emulators before promoting schema or rule changes to production.
- Keep Server & Client Boundaries Type-Safe: Use the modular Firebase Web SDK and generated TypeScript bindings so SSR frameworks like Next.js, Astro, SvelteKit, and Angular serialize state cleanly without hydration flickers.
Conclusion
Accelerate your full-stack web and AI development by pairing Transactions Updates for Data Connect with strict Security Rules, Firebase App Check, and local emulator testing. Come tell us on X (@CodingCatDev) and LinkedIn (CodingCat.dev) how you are using Firebase in your stack, and subscribe to the CodingCat.dev YouTube Channel so you don't miss what we build next!
Watch Our Related Firebase Video Tutorial on YouTube
Want to see how we architect and debug Firebase web applications live? Watch our related CodingCat.dev session Firebase SQL with Data Connect below, and make sure to Subscribe to CodingCat.dev on YouTube for weekly full-stack web and AI deep dives:
Resources, Official Docs & Related CodingCat.dev Guides
- Primary Release Source: Transactions Updates for Data Connect on the Official Firebase Blog (published 2025-06-05 by Andrea Wu)
- Official Firebase Documentation: Firebase Developer Docs & Web SDK Reference
- Related on CodingCat.dev: Server Value Expressions for Data Connect
- Related on CodingCat.dev: Introducing hybrid on-device inference using Firebase AI Logic
- Related on CodingCat.dev: Firebase SQL with Data Connect
- Related on CodingCat.dev: Build a Custom No-Code App in 90 Minutes
Frequently Asked Questions (FAQ)
What are the key capabilities introduced in Transactions Updates for Data Connect?
Transactions Updates for Data Connect (announced 2025-06-05 by the Firebase team) enhances the platform for Firebase, Google Cloud, Web Dev, SQL, TypeScript, Security workloads. Note: Firebase Data Connect has been renamed to SQL Connect. Learn more in the SQL Connect announcement. Developers can review the primary announcement on the Firebase Blog alongside our implementation patterns and production checklist above.
How do web developers use Transactions Updates for Data Connect with Next.js, SvelteKit, React, or Angular?
Web developers can integrate these features using the modular Firebase JavaScript/TypeScript SDK, Firebase Data Connect web bindings, and Firebase App Hosting. Always pair client-side SDK initialization with Firebase App Check and strict Security Rules, and test locally with the Firebase Local Emulator Suite before deploying.
Where can I watch video tutorials on Firebase Web and AI development?
You can watch our hands-on Firebase video walkthroughs on the CodingCat.dev YouTube Channel, including Firebase SQL with Data Connect, and follow us on X (@CodingCatDev) for weekly full-stack tutorials.