Project Structure
After running alab init, you get this structure:
myapp/├── alab.yaml # Configuration├── schemas/ # Schema definitions├── migrations/ # Generated migrations└── types/ # IDE support filesDirectory Reference
Section titled “Directory Reference”| Path | Purpose | Editable? |
|---|---|---|
alab.yaml | Project config (database, output paths) | Yes |
schemas/ | Your schema definitions | Yes |
migrations/ | Generated SQL files | No* |
types/ | Generated TypeScript types | No |
*Migrations can be edited for custom SQL, but regenerating will overwrite.
Schema Organization
Section titled “Schema Organization”Astroladb uses a namespace-based organization where folder structure determines table prefixes.
File Naming = Namespaces
Section titled “File Naming = Namespaces”Folders inside schemas/ become namespaces:
schemas/├── auth/│ ├── user.js → auth.user → SQL table: auth_users│ └── session.js → auth.session → SQL table: auth_sessions├── blog/│ ├── post.js → blog.post → SQL table: blog_posts│ └── comment.js → blog.comment → SQL table: blog_comments└── catalog/ ├── product.js → catalog.product → SQL table: catalog_products └── category.js → catalog.category → SQL table: catalog_categoriesNaming Conventions
Section titled “Naming Conventions”- File names:
snake_case, singular (e.g.,user.js,post_comment.js) - References: Use dot notation with namespace (e.g.,
"auth.user") - SQL tables: Auto-generated as
{namespace}_{table_name}(e.g.,auth_user)
Why Namespaces?
Section titled “Why Namespaces?”Namespaces provide logical grouping and prevent naming conflicts:
- auth: User authentication and authorization
- blog: Content management
- catalog: Products and inventory
- orders: E-commerce transactions
- analytics: Tracking and reporting
This makes it easy to understand what each table does at a glance.
Schema File Anatomy
Section titled “Schema File Anatomy”A schema file is a JavaScript module that exports a table definition:
export default table({ id: col.id(), email: col.email().unique(), username: col.username().unique(), password: col.password_hash(), role: col.enum(["admin", "user"]).default("user"), is_active: col.flag(true),}).timestamps();Key Elements
Section titled “Key Elements”| Element | Syntax | Example |
|---|---|---|
| Table definition | table({ ... }) | table({ id: col.id() }) |
| Column types | col.type() | col.email(), col.name() |
| Nullable | .optional() | col.bio().optional() |
| Unique constraint | .unique() | col.email().unique() |
| Default value | .default(value) | col.status().default("active") |
| Relationships | col.belongs_to("ns.table") | col.belongs_to("auth.user") |
| Timestamps | .timestamps() | Adds created_at, updated_at |
| Soft delete | .soft_delete() | Adds deleted_at |
| Indexes | .index("col1", "col2") | Composite index |
| Unique composite | .unique("col1", "col2") | Multi-column uniqueness |
Column Definition Pattern
Section titled “Column Definition Pattern”Every column follows this pattern:
columnName: col.semanticType().modifier1().modifier2()Examples:
email: col.email().unique(),bio: col.text().optional(),price: col.money().min(0),category: col.belongs_to("catalog.category").on_delete("restrict"),Config File
Section titled “Config File”The alab.yaml configures your project:
database: dialect: postgres url: postgres://user:pass@localhost:5432/mydb
schemas: ./schemasmigrations: ./migrations