ESC
Type to search...
S
Soli Docs

Database Migrations

Evolve your database schema with versioned migration files. Create collections, indexes, and manage schema changes safely.

Overview

Migrations are stored in db/migrations/ with timestamped filenames. Each migration contains up() and down() functions for applying and rolling back changes.

db/migrations/20260122143052_create_users.soli
fn up(db: Any) -> Any {
    db.create_collection("users");
    db.create_index("users", "idx_email", ["email"], { "unique": true });
}

fn down(db: Any) -> Any {
    db.drop_index("users", "idx_email");
    db.drop_collection("users");
}

CLI Commands

generate Create a Migration

soli db:migrate generate create_users_table

Creates: db/migrations/20260122143052_create_users_table.soli

up Run Migrations

# Apply all pending migrations
soli db:migrate

# Or explicitly
soli db:migrate up

down Rollback

# Rollback the last migration
soli db:migrate down

status Check Status

soli db:migrate status
  Database Migrations

  Version         Name                            Status
  --------------  ------------------------------  ----------
  20260122143052  create_users_table                 up
  20260122145201  add_posts_table                    up
  20260122151033  add_user_indexes                  down

  2 applied, 1 pending

Collection Helpers

db.create_collection(name)

Create a new collection (table).

db.drop_collection(name)

Remove a collection and all its data.

db.list_collections()

List all collections in the database.

db.collection_stats(name)

Get statistics for a collection.

Collection Examples
fn up(db: Any) -> Any {
    db.create_collection("users");
    db.create_collection("posts");
    db.create_collection("comments");
}

fn down(db: Any) -> Any {
    db.drop_collection("comments");
    db.drop_collection("posts");
    db.drop_collection("users");
}

Index Helpers

db.create_index(collection, name, fields, options)

Create an index on a collection.

  • fields - Array of field names: ["email"] or ["first_name", "last_name"]
  • options - Hash with unique: true and/or sparse: true
db.drop_index(collection, name)

Remove an index from a collection.

db.list_indexes(collection)

List all indexes for a collection.

Index Examples
fn up(db: Any) -> Any {
    // Simple index
    db.create_index("users", "idx_email", ["email"], {});

    // Unique index
    db.create_index("users", "idx_username", ["username"], { "unique": true });

    // Sparse index (only indexes documents with the field)
    db.create_index("users", "idx_phone", ["phone"], { "sparse": true });

    // Compound index on multiple fields
    db.create_index("users", "idx_name", ["first_name", "last_name"], {});

    // Unique compound index
    db.create_index("posts", "idx_user_slug", ["user_id", "slug"], { "unique": true });
}

fn down(db: Any) -> Any {
    db.drop_index("posts", "idx_user_slug");
    db.drop_index("users", "idx_name");
    db.drop_index("users", "idx_phone");
    db.drop_index("users", "idx_username");
    db.drop_index("users", "idx_email");
}

Raw Queries

For operations not covered by helpers, use raw SDBQL queries:

fn up(db: Any) -> Any {
    // Insert seed data
    db.query("INSERT { name: 'Admin', role: 'admin' } INTO users");

    // Update existing data
    db.query("FOR u IN users FILTER u.role == 'guest' UPDATE u WITH { role: 'user' } IN users");
}

Complete Example

A migration for a blog application:

db/migrations/20260122143052_create_blog_schema.soli
fn up(db: Any) -> Any {
    // Create collections
    db.create_collection("users");
    db.create_collection("posts");
    db.create_collection("comments");
    db.create_collection("tags");

    // User indexes
    db.create_index("users", "idx_users_email", ["email"], { "unique": true });
    db.create_index("users", "idx_users_username", ["username"], { "unique": true });

    // Post indexes
    db.create_index("posts", "idx_posts_author", ["author_id"], {});
    db.create_index("posts", "idx_posts_slug", ["slug"], { "unique": true });
    db.create_index("posts", "idx_posts_published", ["published_at"], { "sparse": true });

    // Comment indexes
    db.create_index("comments", "idx_comments_post", ["post_id"], {});
    db.create_index("comments", "idx_comments_author", ["author_id"], {});

    // Tag indexes
    db.create_index("tags", "idx_tags_name", ["name"], { "unique": true });
}

fn down(db: Any) -> Any {
    // Drop indexes first
    db.drop_index("tags", "idx_tags_name");
    db.drop_index("comments", "idx_comments_author");
    db.drop_index("comments", "idx_comments_post");
    db.drop_index("posts", "idx_posts_published");
    db.drop_index("posts", "idx_posts_slug");
    db.drop_index("posts", "idx_posts_author");
    db.drop_index("users", "idx_users_username");
    db.drop_index("users", "idx_users_email");

    // Drop collections
    db.drop_collection("tags");
    db.drop_collection("comments");
    db.drop_collection("posts");
    db.drop_collection("users");
}

Environment Configuration

Configure database connection via .env file:

.env
SOLIDB_HOST=http://localhost:6745
SOLIDB_DATABASE=myapp_development
SOLIDB_USERNAME=root
SOLIDB_PASSWORD=secret

Best Practices

  • Keep migrations small - One logical change per migration
  • Always write down() - Enable clean rollbacks
  • Test rollbacks - Run down then up to verify
  • Order matters in down() - Drop indexes before collections
  • Don't modify old migrations - Create new ones for changes

Helpers Reference

Method Description
db.create_collection(name) Create a new collection
db.drop_collection(name) Drop a collection
db.list_collections() List all collections
db.collection_stats(name) Get collection statistics
db.create_index(collection, name, fields, options) Create an index
db.drop_index(collection, name) Drop an index
db.list_indexes(collection) List indexes for a collection
db.query(sdbql) Execute a raw SDBQL query

Next Steps