Per-Release Databases and Atomic Deployment: The Rollback Story
Per-release databases mean schema changes apply to a clone, not live data. Rollback is atomic: code, schema, and data revert together in one step.
TL;DR
- Remy clones the database on every deploy — schema changes apply to the clone, never to live data — so a failed migration can’t corrupt production.
- Each release gets its own database snapshot, making rollback atomic: code, schema, and data revert together in a single step.
- The build pipeline (read the spec → create a release → compile methods and interfaces → diff schemas → apply changes atomically) runs in ~10–15 seconds for typical apps.
- Most teams don’t build this for themselves — they treat schema migrations as a separate, manual step that breaks atomicity and makes rollback risky.
- When DDL fails, the live database is untouched and the release is marked
failed— no downtime, no partial state, no manual cleanup. - The same architecture powers dev sessions: reset from live data or truncate to empty tables with a single command, preserving IDs so the frontend never needs a reload.
Most deployment pipelines treat code and database as separate concerns. You push code, run migrations by hand, hope nothing breaks, and cross your fingers that rollback won’t leave the schema in a half-migrated state. Remy treats the database as part of the release artifact — clone, migrate, promote atomically — so rolling back is a one-step deploy, not a recovery procedure.
What happens when you publish a new release?
Everyone else built a construction worker.
We built the contractor.
One file at a time.
UI, API, database, deploy.
Every time you hit Publish, the build pipeline runs. The platform reads your spec, compiles methods and interfaces, parses table schemas, diffs against the live database, and applies all changes atomically. The entire process takes 10–15 seconds for a typical app.
Step 1: Read the spec
The platform reads what your app declares — methods, tables, roles, interfaces, and scenarios. This is the source of truth for what the app does and how it’s structured.
Step 2: Create the release
A new release is created with status building. This tracks the entire deploy — the build log, the pending changes, which database the release points at, and when it went live.
Step 3: Snapshot the files
The app’s files are copied so the editor can access them instantly, giving you a fast file tree the moment you open the sandbox.
Step 4: Compile methods
Each method is bundled into a single JavaScript file. The platform pulls in the npm packages the method depends on and pre-installs them in the execution sandbox. Methods run in isolated containers with db and auth available to them automatically.
Step 5: Compile interfaces
The web interface is built, and the API, Discord, Telegram, cron, webhook, email, MCP, and agent interfaces generate their config files. Each interface is a projection of the backend contract into a different modality — same methods, different invocation surface.
Step 6: Parse table schemas
The platform reads your table definitions and extracts the column definitions. It compares against the current live database schema and generates DDL: CREATE TABLE for new tables, ALTER TABLE ADD COLUMN for new columns, ALTER TABLE DROP COLUMN for removed columns, DROP TABLE for removed tables.
Type changes and renames aren’t supported in the automatic migration path — those require manual intervention. But the 90% case (add a column, add a table, remove a column) is automatic.
Step 7: Compute and apply pending changes
The platform computes everything that needs to change: roles, cron jobs, bot commands, webhook and email routing, and table DDL. These are staged on the release. Nothing changes in the live system yet.
When the release is promoted to live, all effects apply atomically:
- Roles: create new roles, update descriptions, delete removed roles
- Cron: upsert scheduled jobs (create/update/remove)
- Discord: sync slash commands via Discord API
- Telegram: sync bot commands via Telegram API
- Webhooks: update endpoint registrations
- Email: update email trigger routing
- Tables: clone the live database, apply DDL to the clone, promote the clone to live
The database clone-and-promote is the critical step. Schema changes are always applied to a clone, never to the live database directly. If the DDL fails, the live database is untouched and the release is marked failed.
Why per-release databases matter
Most deployment pipelines treat the database as a singleton. You run migrations against the live database, hope they succeed, and deal with the fallout if they don’t. Rollback is manual: write a down-migration, test it in staging, run it in production, hope it works.
Remy’s per-release database model makes rollback atomic. Each release gets its own database copy. The live release has the production database. A new release clones from live, applies DDL, then becomes the new live database on promotion.
The fastest way to roll back: re-promote a previous release from the editor dashboard. The previous release’s database snapshot becomes live again instantly — no rebuild, no migration, just a switch back to a known-good release. Because each release keeps its own database snapshot, code, schema, and data all revert together.
If you’d rather roll back through your normal workflow, revert the change and hit Publish again. That deploys the reverted version, and the previous release’s database is still available, so data isn’t lost either way.
How schema changes work in practice
Add a column to a table:
export const Vendors = db.defineTable<{
name: string;
contactEmail: string;
status: 'pending' | 'approved' | 'rejected';
taxId: string;
paymentTerms?: string;
// New column
notes?: string;
}>('vendors');
Hit Publish. The platform:
- Parses the TypeScript file and extracts the schema
- Diffs against the live database:
vendorstable exists,notescolumn does not - Generates
ALTER TABLE vendors ADD COLUMN notes TEXT - Clones the live database to a staging copy
- Applies the DDL to the staging copy
- Promotes the staging copy to live
If the DDL fails (syntax error, constraint violation, whatever), the live database is untouched. The release is marked failed and the build log captures the error. Fix the issue and publish again.
Drop a column:
export const Vendors = db.defineTable<{
name: string;
contactEmail: string;
status: 'pending' | 'approved' | 'rejected';
taxId: string;
// paymentTerms removed
}>('vendors');
The platform generates ALTER TABLE vendors DROP COLUMN paymentTerms and applies it to the clone. The live database keeps the column until the new release is promoted.
Add a table:
export const Invoices = db.defineTable<{
poId: string;
invoiceNumber: string;
amountCents: number;
dueDate: number;
status: 'pending_review' | 'approved' | 'paid';
}>('invoices');
Hit Publish. The platform generates CREATE TABLE invoices (...) with all your columns, the standard bookkeeping columns (a unique ID, created/updated timestamps), and indexes. The table exists in the new release’s database but not in the previous release’s database.
What most teams don’t build
Per-release databases with atomic schema migration is not the default in most stacks. The typical pattern:
- Write a migration file by hand
- Test it in staging
- Run it in production during a maintenance window
- Hope it works
- If it breaks, write a down-migration and run it manually
This works until it doesn’t. A failed migration leaves the database in a half-migrated state. Rollback is a recovery procedure, not a one-step deploy. You’re debugging schema state at 2am.
Remy’s architecture makes this impossible. Schema changes apply to a clone. If the DDL fails, the live database is untouched. If the release is promoted and something breaks, you re-promote the previous release and its database snapshot becomes live again — or revert the change and hit Publish.
Each app gets its own serverless SQL database, with schema changes applied to clones before promotion. It’s not exotic — it’s the right architecture for the workload shape most business applications produce.
How dev sessions use the same architecture
Other agents start typing. Remy starts asking.
Scoping, trade-offs, edge cases — the real work. Before a line of code.
Dev sessions get their own database, a snapshot of the live database at session start. Your dev code writes to this snapshot, not to production. Two operations are available:
Reset from live data
Overwrite the dev database with a fresh copy of production data. This preserves your existing data references, so nothing on the frontend needs to reload — useful when you want to test against real data or when your dev database has accumulated test cruft.
Truncate (empty tables)
Keep the schema, delete all the row data. This gives you a clean canvas before seeding test data, and it also preserves your data references so the frontend keeps working without a reload.
Both operations are the same clone-and-promote architecture applied to dev workflows.
When the managed database path isn’t the right fit
For workloads that legitimately need a different engine — extreme data volumes, complex cross-table transactions on hundreds-of-GB datasets, dedicated database tier, specific cloud-residency mandates outside what the managed path supports — there’s nothing structural stopping you from connecting an external database. Remy-generated app code is standard TypeScript and can call any database client a Node.js app can call.
The managed serverless SQL database path covers most business-application workloads cleanly. The escape hatch exists for the genuinely unusual cases, not because the managed path is itself a bottleneck. Modern serverless SQL databases are production-grade — they handle concurrent reads and writes comfortably, run well past a gigabyte without operational stress, and sit on top of a serious, growing ecosystem of cloud-scale serverless SQL.
The question isn’t whether serverless SQL is production-ready — it is. The question is which deployment pattern fits which workload. For apps where writes correlate with user actions (internal tools, vertical SaaS, approval workflows, CRM-shaped apps), a per-app serverless SQL database with atomic schema migration is the right answer.
How this compares to coding agents and app builders
Coding agents like Cursor and Claude Code edit code in a project you already own and deploy. They don’t compile a spec into a deployed app with a managed database. You’re responsible for the deployment pipeline, the database, the schema migrations, the rollback strategy.
AI app builders like Lovable and Bolt generate a frontend you keep re-prompting. Some now ship a backend (Lovable Cloud is Supabase under the hood; Bolt V2 ships a database and auth), but the architecture is still prompt-driven code generation, not spec-driven compilation. The chat log is the only history of intent. When AI models get better, you have to re-prompt your way back to the same app. With Remy, you recompile the same spec into a better app.
The structural difference that holds even when competitors add features: Remy is spec-driven compilation. The spec is the source of truth. The code is compiled output. The database is part of the release artifact. Rollback is atomic. This is a different abstraction layer than “chat with an AI that emits code.”
The bottom line
- ✕a coding agent
- ✕no-code
- ✕vibe coding
- ✕a faster Cursor
The one that tells the coding agents what to build.
Per-release databases with atomic schema migration is the architecture that makes rollback safe. Schema changes apply to a clone, not to live data. If the DDL fails, the live database is untouched. If the release is promoted and something breaks, you re-promote the previous release in one step. Code, schema, and data revert together.
Most teams don’t build this for themselves. They treat schema migrations as a separate, manual step that breaks atomicity and makes rollback risky. Remy treats the database as part of the release artifact — clone, migrate, promote atomically — so rolling back is a one-step deploy, not a recovery procedure.
It’s not exotic. It’s the right architecture for the workload shape most business applications produce.
Remy is a product agent that compiles annotated markdown into a full-stack app — backend, database, frontend, auth, tests, and deployment — in a single step.
FAQ
How long does a deploy take?
10–15 seconds for a typical app. The platform compiles methods, builds interfaces, parses schemas, clones the database, applies DDL, and promotes atomically. The build log captures every step with timing.
What happens if a migration fails?
The live database is untouched and the release is marked failed. The build log captures the error. Fix the issue and publish again. No downtime, no partial state, no manual cleanup.
Can I roll back a release?
Yes. The fastest way is to re-promote a previous release from the editor dashboard — its database snapshot becomes live again instantly, with no rebuild. You can also revert the change and hit Publish to deploy the reverted version. Either way, the previous release’s database is still available, so data isn’t lost.
What if I need to change a column type or rename a column?
Type changes and renames aren’t supported in the automatic migration path. You’ll need to write a custom migration script or handle the change manually. The 90% case (add a column, add a table, remove a column) is automatic.
How does this work for dev sessions?
Dev sessions get their own database, a snapshot of the live database at session start. You can reset from live data or truncate to empty tables with a single command. Both operations preserve IDs, so the frontend never needs a reload.
What if my app needs a different database engine?
Remy-generated app code is standard TypeScript and can call any database client a Node.js app can call. For workloads that need Postgres, MySQL, or another engine, you can connect an external database. The managed serverless SQL database path covers most business-application workloads cleanly, but the escape hatch exists for genuinely unusual cases.
How does per-release database storage scale?
Each release’s database is stored in object storage. Old releases are retained for a configurable period (default 30 days) and then pruned. The storage cost is negligible for most apps — serverless SQL databases compress well and object storage is cheap.
What’s the difference between Remy and a coding agent for deployment?
Seven tools to build an app. Or just Remy.
Editor, preview, AI agents, deploy — all in one tab. Nothing to install.
Coding agents like Cursor and Claude Code edit code in a project you already own and deploy. You’re responsible for the deployment pipeline, the database, the schema migrations, the rollback strategy. Remy compiles a spec into a deployed app with a managed database, atomic schema migration, and one-step rollback. Different abstraction layer, different job.
How does Remy stay useful as AI models improve?
The spec is the source of truth; code is compiled output. When models improve, recompile the same spec and the app upgrades automatically. You don’t have to re-prompt your way back to the same app — the spec persists, the compiler gets better.