Your First Project
This tutorial walks through creating a project from scratch. By the end you will have two tables in a database with generated types.
Initialize the project
Section titled “Initialize the project”alab initThis creates:
project/├── alab.yaml├── schemas/├── migrations/└── types/Edit alab.yaml to point at a database. For this tutorial, SQLite is the
easiest option:
database: dialect: sqlite url: ./dev.db
schemas: ./schemasmigrations: ./migrationsDefine a users table
Section titled “Define a users table”alab table auth userOpen schemas/auth/user.js and define the columns:
export default table({ id: col.id(), email: col.email().unique(), username: col.username(), password: col.password_hash(), is_active: col.flag(true),}) .timestamps();A few things to notice:
col.email()is a semantic type — it produces aVARCHAR(255)with an OpenAPIformat: "email"hint and a validation pattern. You could writecol.string(255)instead, but the semantic version carries more metadata.col.password_hash()is hidden from API exports. It exists in the database but won’t appear in generated types or OpenAPI output.col.flag(true)defaults totrue— no need to chain.default(true)..timestamps()addscreated_atandupdated_atcolumns automatically.
Define a posts table
Section titled “Define a posts table”alab table blog postEdit schemas/blog/post.js:
export default table({ id: col.id(), title: col.title(), slug: col.slug(), body: col.body(), status: col.enum(["draft", "published", "archived"]).default("draft"), author: col.belongs_to("auth.user"),}) .timestamps() .soft_delete();col.slug()is automatically unique with a slug-format validation pattern.col.belongs_to("auth.user")creates anauthor_idforeign key column referencingauth_user.id..soft_delete()adds a nullabledeleted_atcolumn.
Generate and apply the migration
Section titled “Generate and apply the migration”alab new initial_schemaThis compares your schema files against an empty state and generates
migrations/001_initial_schema.js with up() and down() functions.
Preview the SQL:
alab migrate --dryApply it:
alab migrateCheck the result
Section titled “Check the result”alab statusThis opens a TUI showing your schema state, migration history, and
verification status. You should see both tables created with all columns,
indexes, and the foreign key from blog_post.author_id to auth_user.id.
What you have now
Section titled “What you have now”- Two tables (
auth_user,blog_post) in your database - A migration file that can be rolled back with
alab rollback - TypeScript definitions for IDE support
- A schema that serves as the single source of truth for everything downstream