Workspace CLI
The informer-workspace command manages your app's local development database (workspace). It creates an isolated Postgres schema on the Informer server where your migrations/*.sql files are applied.
Setup
Add these scripts to your package.json (added automatically by informer-init):
{
"scripts": {
"workspace:init": "informer-workspace init",
"workspace:migrate": "informer-workspace migrate",
"workspace:reset": "informer-workspace reset"
}
}
All workspace commands accept --mode <name> to target a specific environment (see Environment Variables):
# Initialize workspace on test server (loads .env.test)
npm run workspace:init -- --mode test
Commands
workspace:init
Creates a new workspace datasource and runs all migrations:
npm run workspace:init
This command:
- Creates a workspace datasource named
{package-name}-devon the Informer server - Creates a
_migrationstracking table in the workspace schema - Runs all
.sqlfiles inmigrations/in alphabetical order - Saves
INFORMER_DEV_WORKSPACE={naturalId}to the active env file (.envby default, or.env.<mode>when using--mode)
You typically run this once when setting up a new project. After that, the Vite plugin auto-runs pending migrations on npm run dev.
workspace:migrate
Runs any pending migrations that haven't been applied yet:
npm run workspace:migrate
This is useful when you've added new migration files and want to apply them without restarting the dev server.
workspace:reset
Drops all tables in the workspace and re-runs all migrations from scratch:
npm run workspace:reset
This gives you a clean database. Use it when:
- Your migrations have gotten out of sync
- You want to test migrations from a clean slate
- You've modified an existing migration file (not recommended in production, but useful during development)
workspace:reset drops all tables in the dev workspace, including any data you've inserted. This is irreversible.
How It Works
The workspace is a regular Informer datasource of type workspace. It gets its own Postgres schema, isolated from other tenants and apps.
Migration Tracking
The _migrations table tracks which migrations have been applied:
CREATE TABLE _migrations (
name TEXT PRIMARY KEY,
executed_at TIMESTAMPTZ DEFAULT NOW()
);
When you run migrations, the system:
- Reads all
.sqlfiles frommigrations/(sorted alphabetically) - Queries
_migrationsfor already-applied names - Runs only the pending ones, in order
- Records each successful migration in
_migrations
Auto-Provisioning
When you run npm run dev with a migrations/ directory present, the Vite plugin automatically:
- Checks if
INFORMER_DEV_WORKSPACEexists in.env - If it does, verifies the datasource still exists on the server and runs pending migrations
- If it doesn't (or the datasource was deleted), recreates the workspace automatically
This means you rarely need to run workspace:init manually — the dev server handles it, including recovering from deleted workspaces.
Dev vs Production Workspaces
| Dev Workspace | Production Workspace | |
|---|---|---|
| Created by | workspace:init or auto-provisioned | _deploy endpoint on deploy |
| Schema name | Derived from datasource ID | Derived from app ID + tenant |
| Migration source | Local migrations/ files | Files uploaded to app library |
| Accessed via | query() in server handlers | query() in server handlers |
| Data | Test/dev data | Real production data |
The dev workspace is completely separate from the production workspace. Deploying your app doesn't affect your dev data, and vice versa.
Writing Migrations
Migration files are plain SQL in the migrations/ directory:
migrations/
001-create-orders.sql
002-add-status.sql
003-add-indexes.sql
Rules
- Alphabetical naming — Use numeric prefixes (
001-,002-, etc.) to control execution order - Append-only — Never modify a migration that has been deployed. Add a new file instead.
- Standard SQL — Use any Postgres-compatible SQL (DDL, DML, functions, etc.)
- One transaction per file — Each migration runs in its own transaction. If it fails, that migration is rolled back but previous successes are preserved.
Example
-- migrations/001-create-orders.sql
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
customer TEXT NOT NULL,
total NUMERIC(10,2) DEFAULT 0,
status TEXT DEFAULT 'pending',
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- migrations/002-add-line-items.sql
CREATE TABLE line_items (
id SERIAL PRIMARY KEY,
order_id INTEGER REFERENCES orders(id) ON DELETE CASCADE,
product TEXT NOT NULL,
quantity INTEGER DEFAULT 1,
price NUMERIC(10,2) NOT NULL
);
CREATE INDEX line_items_order_idx ON line_items (order_id);