PlatformData Model & Database
A production database in every app.
Every Remy app ships with a relational database, and the platform runs all of it: durable, isolated per app, live from the first deploy, with no infrastructure for anyone to set up. It’s the app’s own operational store, built to work alongside the systems a business already has rather than reach into them. Its schema is defined in the app’s own code, typed from the table all the way to the screen.
Production-grade, with nothing to operate.
The app never touches the machinery: no connection strings, no credentials, no backups to schedule, no capacity to plan, no isolation to configure between apps. That’s all the platform’s job.
- No database credentials to leak
- Every query runs through an authenticated platform endpoint, not a direct connection to the database. Because the platform sits in between, it always knows who’s signed in, so it can track who changed what, meter usage, and keep an audit trail automatically. There’s no database password sitting in the app’s code for anyone to steal.
- Per-release isolation, atomic deploys
- Each release gets its own copy of the database, built from the live one, with the schema change applied to that copy before it goes live. Dev, preview, and live are separate databases. A deploy either fully lands or doesn’t happen, and the previous release’s data stays intact underneath it.
- Durable by default
- The database is continuously backed up in the background while the app runs, and mirrored to durable storage. Data lives as a single file, and it’s always recoverable.
Built to work with your systems of record.
Every app carries its own operational store: a purpose-built home for the working data that tool creates and manages as it runs. It works hand in hand with your systems of record, the warehouse or core platform where the authoritative business data lives. The two are built for different jobs and designed to complement each other. The app owns its own working state, and the system of record stays the single authority on the core business data.
Systems of record
They connect through integrations. An app pulls reference data in, pushes results back, or syncs on a schedule, using the platform’s 1,000+ connectors and scheduled jobs. If a workload genuinely needs a live connection instead, the same standard TypeScript code path supports that too. Connecting an app to your system of record is a first-class capability: an integration the app performs, cleanly and on your terms.
Two complementary layers is the stronger design:
- It protects the system of record
- A fleet of tools each holding a direct write connection to the core database is a governance and stability risk. An app working against its own store, integrating through a defined path, can’t overload or corrupt the source of truth.
- The source of truth stays singular
- Apps read and write through defined integrations, so authority over the core data never gets diluted by every tool that touches it.
- Isolation and performance
- A per-app database adds no load to the central system and scales on its own.
- Ownership and portability
- Each app’s data is a portable file the organization owns, exportable on its own, and it integrates with one system of record, several, or none as the work requires.
The engine: SQLite.
Each app’s data lives in its own SQLite database, backed by durable object storage. It’s the same engine behind Cloudflare D1, Turso, and Fly’s LiteFS, and how Notion and Tailscale run in production today. Modern SQLite is a full relational database: transactions, indexes, real concurrency. It’s built for exactly this kind of app.
- File-level backups and residency
- An app’s data is a single file. A backup is a download. Storing that file in a given region gives you data residency in that region.
- No lock-in
- Any standard SQLite client can read the file. Leaving means downloading it and pointing a new data layer at it, not a months-long extraction project.
For the rare case that needs something else (extreme volume, heavy cross-table transactions over hundreds of gigabytes, a mandated dedicated database), Remy’s code is standard TypeScript. It can talk to any database a Node app can.
That is the technical shape of the data. Its organizational shape matters just as much: where each app’s data is stored, how it’s governed, and what the platform can attest to about it. Because every app’s data is one isolated file the platform operates, those become controls the organization inherits rather than work the builder has to do. Data residency across four regions, the audited security posture, and the compliance that travels with the data are covered in Security, Scale & Reliability.
The schema is the code.
For the person building, the data model isn’t a separate file to keep in sync. A table is a TypeScript interface, one line to define it. That interface is the schema: the shape of the database, the type on every read and write, the contract the rest of the app relies on. There are no migration files.
// Written by Remy from your spec interface Vendor { name: string; contactEmail: string; status: 'pending' | 'approved' | 'rejected'; paymentTerms?: string; } export const Vendors = db.defineTable<Vendor>('vendors', { unique: [['contactEmail']], });
On deploy, the platform reads the table definitions, compares them to the live database, and works out the change itself: new tables, new columns, columns to drop. It applies the change to a fresh copy of the database, then switches that copy live. Nothing to write, order, or replay by hand.
Traditional migration tools treat the schema as a log of change scripts, applied in order. Skip one, and the database quietly drifts from what the code expects, with no type checking to catch it. When the interface is the schema, there’s nothing to drift and nothing to forget.
One thing is deliberately not automatic. Renames and type changes are handled explicitly, not guessed. The platform won’t infer a change that could destroy live data on its own.
Typed from the table to the interface.
The type doesn’t stop at the schema. The same interface that defines the database shape also defines what every read and write returns, and what your methods and your interface consume. One contract holds from the table all the way to the screen.
Change a column, and the compiler flags every read and write that no longer fits. A misspelled column name, a mismatched shape, a forgotten field: bugs that would otherwise show up in production instead show up as compile errors, before the app ever ships.
A few things fall out of that:
- Typed queries
- A filter is checked against the interface and compiled into the actual database query. No hand-written SQL strings, no untyped query-building.
- Consistent everywhere
- The same row type a backend method returns is the exact type the frontend consumes.
- Record-keeping for free
- Every table automatically gets an id, created and updated timestamps, and a record of who last changed it, filled in for you based on whoever’s signed in.
Any one of these holds up on its own. Together, they compound. A platform-run database gives every app durability, isolation, and safe deploys, with no operational work. Per-app SQLite on durable storage means all of that scales cleanly: a portable file, no lock-in. A schema defined in code can’t silently drift from that code, and it’s safe for an agent to change. Describe an app in a sentence, have the agent build it, and what comes out still has a correct relational schema, production-grade durability, and its own isolated database, with no infrastructure for anyone to run.
Start building on Remy.
Describe the app. The database comes with it.
Start building← Back to the Platform