BaasixBaasix

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

CommandDescription
baasix initCreate a new Baasix project with interactive configuration
baasix generateGenerate TypeScript types from your Baasix schemas
baasix extensionScaffold a new extension (hook or endpoint)
baasix migrateRun 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 -y

Options

OptionDescription
-n, --name <name>Project name
-t, --template <type>Project template: api, nextjs, or nextjs-app
-y, --yesSkip 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 uploads

Next.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.md

Next.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.local

Architecture 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:

  1. Project Name: Your project name
  2. Template: API, Next.js App Router, or Next.js Pages
  3. Database URL: PostgreSQL connection string
  4. Multi-tenancy: Enable tenant isolation
  5. Public Registration: Allow self-signup
  6. Real-time Features: Enable WebSocket support
  7. Storage Driver: LOCAL or S3-compatible storage
  8. Cache Adapter: Memory or Redis caching
  9. Auth Services: Select OAuth providers (Google, GitHub, etc.)
  10. 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 dev

Type 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 SettingRequirements
SCHEMAS_PUBLIC=true (default)Any authenticated user credentials
SCHEMAS_PUBLIC=falseAdmin 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 collectionsBaasixUser, 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 -y

Options

OptionDescriptionDefault
--url <url>Baasix API URLhttp://localhost:8056
-o, --output <path>Output file pathbaasix.d.ts
-t, --target <target>Generation targetInteractive
-y, --yesSkip confirmation prompts-

Generation Targets

TargetDescription
typesTypeScript interfaces for all collections
sdk-typesTyped SDK helpers with collection methods
schema-jsonExport 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 | null

Extension 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 orders

Options

OptionDescription
-t, --type <type>Extension type: hook or endpoint
-n, --name <name>Extension name
--collection <name>Collection name (for hooks)
--typescriptUse TypeScript (default)
--no-typescriptUse 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:

HookDescription
items.createBefore/after creating an item
items.readBefore/after reading items
items.updateBefore/after updating an item
items.deleteBefore/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:8056

Actions

ActionDescription
statusShow migration status (pending/executed)
listList all local migrations
runRun pending migrations
createCreate a new migration file
rollbackRollback the last batch
resetRollback all migrations (dangerous!)

Options

OptionDescription
--url <url>Baasix API URL
-n, --name <name>Migration name (for create)
-s, --steps <number>Number of batches to rollback
-y, --yesSkip confirmation prompts

Creating Migrations

baasix migrate create --name add-products-table

This 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 1

Environment Variables

The CLI respects these environment variables:

VariableDescription
BAASIX_URLDefault API URL for commands
BAASIX_EMAILDefault admin email
BAASIX_PASSWORDDefault admin password
BAASIX_TOKENJWT token for authentication

You can set these in a .env file:

BAASIX_URL=http://localhost:8056
BAASIX_EMAIL=admin@baasix.com
BAASIX_PASSWORD=admin@123

Best 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 handlers

Type Generation Workflow

  1. Start your Baasix server
  2. Create/modify schemas via API or Admin UI
  3. Run baasix generate to update types
  4. 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 build

Troubleshooting

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 .env or 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

On this page