Skip to content

Tables

Scaffold a new table file with:

Terminal window
alab table blog post

This creates schemas/blog/post.js where blog is the namespace and post is the table name. The resulting database table is blog_post.

Define tables using the table({...}) function:

export default table({
id: col.id(),
title: col.title(),
body: col.text(),
published: col.flag(),
author: col.belongs_to("auth.user"),
});

Every key becomes a column. The value is a column builder — either a low-level type like col.string() or a semantic type like col.title().

Columns support chained modifiers to add constraints:

export default table({
id: col.id(),
email: col.email().unique(),
username: col.username(),
bio: col.text().optional(),
role: col.enum(["admin", "editor", "viewer"]).default("viewer"),
});
ModifierWhat it does
.optional()Allows NULL values
.unique()Adds a unique constraint
.default(value)Sets a default value

Chain modifiers on the table itself to add common functionality:

schemas/blog/article.js
export default table({
id: col.id(),
title: col.title(),
body: col.body(),
})
.timestamps()
.soft_delete()
.searchable(["title", "body"]);
ModifierWhat it adds
.timestamps()created_at and updated_at datetime columns (auto-managed)
.auditable()created_by and updated_by UUID columns
.soft_delete()Nullable deleted_at datetime column
.sortable()position integer column for manual ordering

These don’t add columns — they annotate the table in the OpenAPI x-db extension for downstream consumers (generators, custom tooling).

ModifierWhat it does
.sort_by(["col1", "col2"])Default ORDER BY columns for queries
.searchable(["col1"])Marks columns for full-text search indexing
.filterable(["col1"])Marks which columns can be filtered in queries
ModifierWhat it does
.unique("col1", "col2")Composite unique constraint across columns
.index("col1", "col2")Composite index across columns
.many_to_many("other.table")Many-to-many relationship (auto-creates a join table)
.junction(...refs)Marks explicit junction table for M2M (allows custom cols)

A realistic table definition combining columns, modifiers, and relationships:

schemas/blog/post.js
export default table({
id: col.id(),
title: col.title(),
slug: col.slug(),
body: col.body(),
published: col.flag(),
author: col.belongs_to("auth.user"),
})
.timestamps()
.soft_delete()
.searchable(["title", "body"])
.index("author", "published");

This produces:

  • A blog_post table with the defined columns
  • created_at, updated_at (from .timestamps())
  • deleted_at (from .soft_delete())
  • A foreign key to auth_user (from col.belongs_to())
  • A composite index on (author, published)
  • The slug column is automatically unique with validation (from col.slug())
  • published defaults to false (from col.flag())
  • Searchable and soft-delete metadata in the OpenAPI x-db extension