One of the most tedious parts of building a web application is writing CRUD boilerplate. With Stacks, your models automatically generate fully typed API endpoints, database migrations, factories, and seeders.

Define a Model, Get an API

Here's what a typical Stacks model looks like:

// app/Models/Post.ts
export default defineModel({
  name: 'Post',
  table: 'posts',
  traits: {
    useTimestamps: true,
    useApi: {
      uri: 'posts',
      routes: ['index', 'store', 'show', 'update', 'destroy'],
    },
  },
  attributes: {
    title: {
      validation: { rule: schema.string().min(3).max(255) },
      factory: faker => faker.lorem.sentence(),
    },
    slug: {
      unique: true,
      validation: { rule: schema.string().min(3).max(255) },
    },
    body: {
      validation: { rule: schema.string() },
    },
  },
})

From this single file, Stacks generates:

  • API routes: GET /api/posts, POST /api/posts, GET /api/posts/:id, PATCH /api/posts/:id, DELETE /api/posts/:id
  • Database migration: Creates the posts table with all columns
  • Factory: Generates realistic test data using Faker
  • Seeder: Populates your database with sample data
  • TypeScript types: Full type inference for queries and responses

Type-Safe Queries

The Stacks ORM is built on Kysely, giving you fully type-safe database queries:

const posts = await db
  .selectFrom('posts')
  .where('status', '=', 'published')
  .orderBy('published_at', 'desc')
  .selectAll()
  .execute()

Every column name, operator, and value is type-checked at compile time. Typos become compile errors, not runtime bugs.

Relationships

Stacks supports all common relationship types with a clean, declarative syntax:

export default defineModel({
  name: 'Post',
  belongsTo: ['Author'],
  traits: { taggable: true, categorizable: true, commentables: true },
})

What's Next

We are working on even more ORM features — real-time subscriptions, full-text search integration, and automatic OpenAPI documentation generation. Stay tuned.