Database

LaunchFast uses SQLite as the database, managed through Prisma ORM. This provides a simple, zero-dependency database that runs anywhere — from local development to production on Fly.io with LiteFS replication.

Why SQLite

SQLite is an embedded database that requires no separate server process. Your database lives alongside your application, reducing operational complexity and latency. For the scale LaunchFast targets (single product, small team), SQLite with LiteFS replication handles both reads and writes efficiently.

Prisma ORM

Prisma provides type-safe database access, schema management, and migration tooling. The schema is defined in prisma/schema.prisma and generates a typed client.

Database access

All database access goes through db.server.ts. This is an architectural invariant — no other module should instantiate or configure the Prisma client directly.

Migrations

Prisma handles database migrations. Migrations run automatically as part of the deployment process (on the primary instance only). To create a new migration:

npx prisma migrate dev --name describe-your-change

Widen-then-narrow strategy

For zero-downtime deploys, avoid breaking schema changes. Instead, use a widen-then-narrow approach across multiple deployments:

  1. Widen the app to read from the new field with a fallback to the old field
  2. Widen the database to have both fields, populating the new from the old
  3. Narrow the app to only use the new field
  4. Narrow the database to remove the old field

Each step is a separate deployment. This ensures running instances are never broken by schema changes.

Seeding

The development seed (prisma/seed.ts) creates test users and data. It runs automatically with prisma migrate reset. For production seeding, add data directly to migration SQL files. See the SQLite operations page for production seeding details.

Role-based access control

LaunchFast includes RBAC with fine-grained permissions. Each user has roles, and each role has permissions. A user's effective permissions are the union of all their roles' permissions.

Default permissions include create, read, update, and delete for user with own and any access levels. Default roles are user and admin.

// Server-side
const user = await requireUserWithPermission(request, 'delete:user:any')
const admin = await requireUserWithRole(request, 'admin')

// Client-side
const user = useUser()
const canCreate = userHasPermission(user, 'create:note:own')
const isAdmin = userHasRole(user, 'admin')

Invariants

Database operations are governed by strict correctness rules (never modify committed migrations, never use prisma db push in production, etc.). See the correctness invariants page for the full list.