Baasix CLI
The Baasix CLI (baasix) is a powerful command-line tool for scaffolding projects, generating TypeScript types, creating extensions, and managing database migrations.
Installation
# Global installation (recommended)
npm install -g baasix
# Or use npx without installation
npx baasix <command>Commands Overview
| Command | Description |
|---|---|
baasix init | Create a new Baasix project with interactive configuration |
baasix generate | Generate TypeScript types from your Baasix schemas |
baasix extension | Scaffold a new extension (hook or endpoint) |
baasix migrate | Run database migrations |
Project Scaffolding (baasix init)
Create a new Baasix project with best practices and proper configuration.
Usage
# Interactive mode
baasix init
# With options
baasix init --name my-app --template api
# Skip prompts with defaults
baasix init --template api -yOptions
| Option | Description |
|---|---|
-n, --name <name> | Project name |
-t, --template <type> | Project template: api, nextjs, or nextjs-app |
-y, --yes | Skip prompts and use sensible defaults |
-c, --cwd <path> | Working directory (default: current) |
Project Templates
API Only (--template api)
Creates a standalone Baasix API server:
my-api/
├── server.js # Entry point
├── package.json # Dependencies
├── .env # Configuration
├── .env.example # Example configuration
├── extensions/ # Custom hooks & endpoints
├── migrations/ # Database migrations
└── uploads/ # File uploadsNext.js App Router (--template nextjs-app)
Creates a frontend-only Next.js 14+ application with Baasix SDK:
my-frontend/
├── src/
│ ├── app/ # Next.js App Router pages
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ └── globals.css
│ └── lib/
│ └── baasix.ts # Pre-configured SDK client
├── package.json
├── .env.local # NEXT_PUBLIC_BAASIX_URL only
└── README.mdNext.js Pages Router (--template nextjs)
Creates a frontend-only Next.js application with Pages Router:
my-frontend/
├── pages/ # Next.js pages
│ ├── _app.tsx
│ └── index.tsx
├── lib/
│ └── baasix.ts # Pre-configured SDK client
├── styles/
│ └── globals.css
├── package.json
└── .env.localArchitecture Note: Next.js templates create frontend-only projects. You need a separate Baasix API server running. Create one with baasix init --template api.
Interactive Configuration
When using interactive mode, the CLI prompts for:
- Project Name: Your project name
- Template: API, Next.js App Router, or Next.js Pages
- Database URL: PostgreSQL connection string
- Multi-tenancy: Enable tenant isolation
- Public Registration: Allow self-signup
- Real-time Features: Enable WebSocket support
- Storage Driver: LOCAL or S3-compatible storage
- Cache Adapter: Memory or Redis caching
- Auth Services: Select OAuth providers (Google, GitHub, etc.)
- OpenAPI: Enable API documentation
Example
$ npx baasix init --template api my-api
┌ Baasix Project Setup
│
◇ Project structure created
│
◇ Dependencies installed
│
└ ✨ Project created successfully!
Next steps:
cd my-api
# Review and update your .env file
npm run devType Generation (baasix generate)
Generate TypeScript types from your Baasix schemas for type-safe development.
Prerequisites
The CLI needs to fetch schemas from your Baasix server. Access depends on the server's SCHEMAS_PUBLIC setting:
| Server Setting | Requirements |
|---|---|
SCHEMAS_PUBLIC=true (default) | Any authenticated user credentials |
SCHEMAS_PUBLIC=false | Admin credentials or role with read permission on baasix_SchemaDefinition |
If you get a 403 Forbidden error, either set SCHEMAS_PUBLIC=true on the server, use admin credentials, or grant your role read access to baasix_SchemaDefinition.
Features
- ✅ Relations — Properly typed as target collection types (not
unknown) - ✅ Enums — Generated as union types (
'published' | 'draft' | 'archived') - ✅ System collections —
BaasixUser,BaasixRole,BaasixFile,BaasixTenant - ✅ Validation JSDoc — Comments with
@min,@max,@length,@format
Usage
# Generate types from running Baasix instance
baasix generate
# With custom options
baasix generate --url http://localhost:8056 --output ./src/types/baasix.d.ts -yOptions
| Option | Description | Default |
|---|---|---|
--url <url> | Baasix API URL | http://localhost:8056 |
-o, --output <path> | Output file path | baasix.d.ts |
-t, --target <target> | Generation target | Interactive |
-y, --yes | Skip confirmation prompts | - |
Generation Targets
| Target | Description |
|---|---|
types | TypeScript interfaces for all collections |
sdk-types | Typed SDK helpers with collection methods |
schema-json | Export schemas as JSON |
Generated Types Example
// System collections (referenced by relations)
export interface BaasixUser {
id: string;
firstName: string;
lastName?: string | null;
email?: string | null;
role_Id: string;
role?: BaasixRole | null;
}
export interface BaasixRole {
id: string;
name: string;
description?: string | null;
}
export interface BaasixFile {
id: string;
filename: string;
type: string;
size: number;
}
// Your collections with proper relation types
export interface Product {
id: string;
name: string;
price: number;
status: 'published' | 'draft' | 'archived'; // Enum as union type
category_Id?: string | null;
category?: Category | null; // M2O relation
userCreated_Id?: string | null;
userCreated?: BaasixUser | null; // System relation
image_Id?: string | null;
image?: BaasixFile | null; // File relation
createdAt?: string;
updatedAt?: string;
}
export interface Category {
id: string;
name: string;
products?: Product[] | null; // O2M relation (HasMany)
}
// Collection name union
export type CollectionName = "products" | "categories";
// Type map for generic helpers
export interface CollectionTypeMap {
products: Product;
categories: Category;
}Using Generated Types
import { createBaasix } from '@tspvivek/baasix-sdk';
import type { Product, Category, BaasixUser } from './types/baasix';
const baasix = createBaasix({
url: 'http://localhost:8056',
});
// Fully typed queries
const { data: products } = await baasix.items<Product>('products').find({
filter: { status: { eq: 'published' } }, // Autocomplete for enum values
fields: ['*', 'category.*', 'userCreated.*'],
});
// products[0].category is typed as Category | null
// products[0].status is typed as 'published' | 'draft' | 'archived'
// products[0].userCreated is typed as BaasixUser | nullExtension Scaffolding (baasix extension)
Create new Baasix extensions with boilerplate code.
Usage
# Interactive mode
baasix extension
# With options
baasix extension --type hook --name order-notifications --collection ordersOptions
| Option | Description |
|---|---|
-t, --type <type> | Extension type: hook or endpoint |
-n, --name <name> | Extension name |
--collection <name> | Collection name (for hooks) |
--typescript | Use TypeScript (default) |
--no-typescript | Use JavaScript |
Extension Types
Hook Extension
Triggered on data operations (create, read, update, delete):
baasix extension --type hook --name audit-log --collection orders// extensions/baasix-hook-audit-log/index.js
export default (hooksService, context) => {
const { ItemsService } = context;
// Before create hook - modify data before saving
hooksService.registerHook('orders', 'items.create', async ({ data, accountability }) => {
data.status = 'pending';
data.created_by = accountability?.user?.id;
return { data };
});
// After create hook - trigger side effects
hooksService.registerHook('orders', 'items.create', async ({ data, result, accountability }) => {
// Send notification, log audit, etc.
console.log(`Order ${result.id} created by ${accountability?.user?.email}`);
});
// Before update hook
hooksService.registerHook('orders', 'items.update', async ({ id, data, accountability }) => {
data.updated_by = accountability?.user?.id;
return { id, data };
});
// Before delete hook
hooksService.registerHook('orders', 'items.delete', async ({ id, accountability }) => {
console.log(`Deleting order ${id}`);
return { id };
});
};Available Hooks:
| Hook | Description |
|---|---|
items.create | Before/after creating an item |
items.read | Before/after reading items |
items.update | Before/after updating an item |
items.delete | Before/after deleting an item |
Endpoint Extension
Custom REST API endpoints:
baasix extension --type endpoint --name analytics// extensions/baasix-endpoint-analytics/index.js
import { APIError } from '@tspvivek/baasix';
export default {
id: 'analytics',
handler: (app, context) => {
const { ItemsService } = context;
// GET endpoint
app.get('/analytics/dashboard', async (req, res) => {
if (!req.accountability?.user) {
throw new APIError('Unauthorized', 401);
}
const { user, role } = req.accountability;
res.json({
message: 'Dashboard data',
user: { id: user.id, email: user.email },
timestamp: new Date().toISOString(),
});
});
// POST endpoint with body
app.post('/analytics/report', async (req, res) => {
if (!req.accountability?.user) {
throw new APIError('Unauthorized', 401);
}
const { startDate, endDate, metrics } = req.body;
// Your analytics logic here
res.status(201).json({
message: 'Report generated',
data: { startDate, endDate, metrics }
});
});
// Parameterized endpoint
app.get('/analytics/:type/:id', async (req, res) => {
const { type, id } = req.params;
res.json({ type, id });
});
},
};Database Migrations (baasix migrate)
Manage database schema migrations.
Usage
# Check migration status
baasix migrate status --url http://localhost:8056
# Run pending migrations
baasix migrate run --url http://localhost:8056Actions
| Action | Description |
|---|---|
status | Show migration status (pending/executed) |
list | List all local migrations |
run | Run pending migrations |
create | Create a new migration file |
rollback | Rollback the last batch |
reset | Rollback all migrations (dangerous!) |
Options
| Option | Description |
|---|---|
--url <url> | Baasix API URL |
-n, --name <name> | Migration name (for create) |
-s, --steps <number> | Number of batches to rollback |
-y, --yes | Skip confirmation prompts |
Creating Migrations
baasix migrate create --name add-products-tableThis creates a timestamped migration file:
// migrations/20240115120000_add-products-table.js
export async function up(baasix) {
// Create a collection
await baasix.schema.create("products", {
name: "Products",
timestamps: true,
fields: {
id: { type: "UUID", primaryKey: true, defaultValue: { type: "UUIDV4" } },
name: { type: "String", allowNull: false, values: { length: 255 } },
price: { type: "Decimal", values: { precision: 10, scale: 2 } },
status: {
type: "Enum",
values: ["published", "draft", "archived"],
defaultValue: "draft"
},
description: { type: "Text" },
},
});
// Add a relationship
await baasix.schema.createRelationship("products", {
name: "category",
type: "M2O",
target: "categories",
});
}
export async function down(baasix) {
await baasix.schema.delete("products");
}Migration Workflow
# 1. Create a migration
baasix migrate create --name add-products-table
# 2. Edit the migration file in migrations/
# 3. Check what will run
baasix migrate status --url http://localhost:8056
# 4. Run migrations
baasix migrate run --url http://localhost:8056
# 5. If something goes wrong, rollback
baasix migrate rollback --url http://localhost:8056 --steps 1Environment Variables
The CLI respects these environment variables:
| Variable | Description |
|---|---|
BAASIX_URL | Default API URL for commands |
BAASIX_EMAIL | Default admin email |
BAASIX_PASSWORD | Default admin password |
BAASIX_TOKEN | JWT token for authentication |
You can set these in a .env file:
BAASIX_URL=http://localhost:8056
BAASIX_EMAIL=admin@baasix.com
BAASIX_PASSWORD=admin@123Best Practices
Project Structure
Organize extensions by type:
extensions/
├── baasix-hook-auth/ # Authentication hooks
├── baasix-hook-notifications/ # Notification triggers
├── baasix-endpoint-reports/ # Custom report endpoints
└── baasix-endpoint-webhooks/ # Webhook handlersType Generation Workflow
- Start your Baasix server
- Create/modify schemas via API or Admin UI
- Run
baasix generateto update types - Use generated types in your frontend/SDK code
CI/CD Integration
# .github/workflows/deploy.yml
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Generate Types
run: npx baasix generate --url ${{ secrets.BAASIX_URL }} -o ./src/types/baasix.d.ts -y
- name: Run Migrations
run: npx baasix migrate run --url ${{ secrets.BAASIX_URL }} -y
- name: Build
run: npm run buildTroubleshooting
Connection Errors
Error: connect ECONNREFUSED 127.0.0.1:8056- Verify your Baasix server is running
- Check the URL is correct
- Ensure no firewall is blocking the connection
Authentication Errors
Error: Authentication failed- Verify admin credentials in
.envor command options - Check if the user has admin privileges
- Ensure the account is not locked
Type Generation Issues
Error: No schemas found- Ensure schemas exist in your Baasix instance
- Verify authentication credentials
- Check API permissions for the authenticated user
Related Documentation
- Deployment Guide — Production deployment
- Baasix Extensions — Extension development in depth
- SDK Guide — Using generated types with SDK
- Database Schema Guide — Schema design best practices