The trail CLI provides commands for managing your TrailBase server, users, migrations, and more.
Installation
The trail binary is included in TrailBase releases:
# Download from GitHub releases
curl -L https://github.com/trailbaseio/trailbase/releases/latest/download/trailbase-linux-x86_64.tar.gz | tar xz
# Make executable
chmod +x trail
# Move to PATH (optional)
sudo mv trail /usr/local/bin/
Global Options
These options work with all commands:
# Specify data directory (default: ./traildepot)
trail --data-dir /var/lib/trailbase run
# Set public URL for OAuth and emails
trail --public-url https://example.com run
# Show version
trail --version
Server Commands
Start Server
Start the HTTP server:
# Start with defaults (localhost:4000)
trail run
# Custom address
trail run --address 0.0.0.0:8080
# Separate admin interface
trail run --admin-address localhost:4001
# Serve static files
trail run --public-dir ./web/dist
# Enable SPA fallback (serve index.html for routes)
trail run --public-dir ./web/dist --spa
# Development mode (permissive CORS)
trail run --dev
# Custom number of WASM workers
trail run --runtime-threads 8
First Run: On first startup, TrailBase creates admin credentials and displays them in the terminal. Save these to access the admin UI at http://localhost:4000/_/admin.
Server Options
Option Description Default --addressServer bind address localhost:4000--admin-addressSeparate admin interface address Same as --address --public-dirStatic file directory None --spaEnable SPA fallback false--runtime-root-fsWASM sandboxed filesystem root None --geoip-db-pathMaxMind GeoIP database path None --devDevelopment mode (permissive CORS) false--demoRedact PII from logs false--cors-allowed-originsAllowed CORS origins *--runtime-threadsNumber of WASM isolates CPU count --stderr-loggingLog to stderr instead of files false
Migration Commands
Create Migration
Generate a new migration file:
# Create migration for main database
trail migration create_table_posts
# Output:
# Created: traildepot/migrations/main/U1234567890__create_table_posts.sql
# Create migration for attached database
trail migration add_analytics_table --db analytics
The generated file is ready to edit:
traildepot/migrations/main/U1234567890__create_table_posts.sql
-- Add your SQL statements here
CREATE TABLE posts (
id INTEGER PRIMARY KEY ,
title TEXT NOT NULL
) STRICT;
Migrations run automatically when TrailBase starts. No separate apply command is needed.
View Applied Migrations
Check which migrations have been applied:
# Using SQLite directly
sqlite3 traildepot/data/main.db "SELECT * FROM _schema_history ORDER BY version;"
User Management
Create User
Add a new verified user:
trail user add user@example.com SecurePassword123
Users created via CLI are automatically verified and can log in immediately.
Change Password
trail user change-password user@example.com NewPassword123
Change Email
trail user change-email old@example.com new@example.com
Verify Email
Manually verify a user’s email:
# Verify user
trail user verify user@example.com true
# Unverify user
trail user verify user@example.com false
Delete User
trail user delete user@example.com
Deleting a user cascades to all records with foreign keys to _user.id. This cannot be undone.
Invalidate Session
Force a user to re-login:
trail user invalidate-session user@example.com
This increments the user’s session version, making existing auth tokens invalid.
Mint Auth Token
Generate an auth token for a user (useful for automation):
trail user mint-token user@example.com
# Output:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
Use the token for API requests:
curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
http://localhost:4000/api/records/todos
Import Users
Import users from Auth0 or other providers:
# Dry run (validate without importing)
trail user import --dry-run --auth0-json users.ndjson
# Actually import
trail user import --auth0-json users.ndjson
Admin Management
List Admins
trail admin list
# Output:
admin@localhost
super@example.com
trail admin promote user@example.com
Demote Admin to User
trail admin demote admin@example.com
You cannot demote yourself. Use another admin account or direct database access.
Schema Commands
Export JSON Schema
Generate JSON Schema for a table:
# Generate schema for SELECT operations
trail schema todos
# Generate schema for INSERT operations
trail schema todos --mode insert
# Generate schema for UPDATE operations
trail schema todos --mode update
Output:
{
"title" : "todos" ,
"type" : "object" ,
"properties" : {
"id" : { "type" : "integer" },
"text" : { "type" : "string" },
"completed" : { "type" : "integer" }
},
"required" : [ "id" , "text" , "completed" ]
}
Pipe to a file for code generation: trail schema todos > schema/todos.json
npx json-schema-to-typescript schema/todos.json > src/types/todos.ts
Export OpenAPI Spec
Generate OpenAPI specification:
# Print to stdout
trail openapi print
# Save to file
trail openapi print > openapi.yaml
# Run Swagger UI (requires swagger feature)
trail openapi run
# Opens http://localhost:4004
Email Commands
Send emails programmatically:
trail email \
--to recipient@example.com \
--subject "Test Email" \
--body "This is a test message."
Email settings must be configured in traildepot/config.textproto or via environment variables.
Component Management
List Available Components
Show first-party WASM components:
trail components list
# Output:
Available first-party components:
- trailbase-guest-ts (TypeScript/JavaScript runtime )
- trailbase-guest-rust (Rust runtime )
Install Component
# Install from registry
trail components add trailbase-guest-ts
# Install from local file
trail components add ./component.wasm
# Install from URL
trail components add https://example.com/component.wasm
List Installed Components
trail components installed
# Output:
Installed components:
- trailbase-guest-ts (v1.0.0)
Update Components
Update all installed first-party components:
Remove Component
trail components remove trailbase-guest-ts
Common Workflows
Development Setup
Create Admin User
trail user add admin@localhost AdminPass123
trail admin promote admin@localhost
Create Schema
trail migration create_initial_schema
# Edit the migration file
# Restart server to apply
Generate Types
trail schema todos > schema/todos.json
npx json-schema-to-typescript schema/todos.json > src/types/todos.ts
Production Deployment
Set Environment Variables
export PUBLIC_URL = https :// example . com
export OBJECT_STORE_TYPE = s3
export OBJECT_STORE_BUCKET = my-bucket
export OBJECT_STORE_ACCESS_KEY_ID = ...
export OBJECT_STORE_SECRET_ACCESS_KEY = ...
Run Server
trail run \
--data-dir /var/lib/trailbase \
--address 0.0.0.0:4000 \
--public-dir /var/www/app
Configure Reverse Proxy
Use nginx, Caddy, or similar to handle:
TLS termination
Request compression
Static file caching
Rate limiting
Database Backup
# Manual backup
cp traildepot/data/main.db backups/main- $( date +%Y%m%d ) .db
# Automated backup script
#!/bin/bash
DATE = $( date +%Y%m%d-%H%M%S )
cp traildepot/data/main.db backups/main- $DATE .db
# Keep only last 7 days
find backups/ -name "main-*.db" -mtime +7 -delete
TrailBase automatically creates backups in traildepot/backups/. These are SQLite database files that can be restored by copying them to traildepot/data/.
Reset Admin Password
If you lose admin credentials:
# Create new admin user
trail user add newadmin@localhost SecurePass123
trail admin promote newadmin@localhost
# Or change existing admin password
trail user change-password admin@localhost NewSecurePass123
Test Configuration
# Validate config by starting server
trail run
# Check logs for errors
tail -f traildepot/logs/trailbase.log
# Test with cURL
curl http://localhost:4000/_/health
Environment Variables
Override CLI options with environment variables:
# Data directory
export DATA_DIR = / var / lib / trailbase
# Public URL
export PUBLIC_URL = https :// example . com
# Server address
export ADDRESS = 0 . 0 . 0 . 0 : 4000
# WASM runtime threads
export RUNTIME_THREADS = 8
# Run server
trail run
Configuration File
Main configuration file: traildepot/config.textproto
Example configuration:
traildepot/config.textproto
server {
application_name: "My App"
site_url: "https: //example.com"
}
auth {
disable_password_auth: false
require_email_verification: true
password_policy {
min_length: 8
require_uppercase: true
require_lowercase: true
require_number: true
}
oauth_providers: [
{
key: "github"
value {
client_id: "your-client-id"
client_secret: "your-client-secret"
provider_id: GITHUB
}
}
]
}
email {
smtp_host: "smtp.gmail.com"
smtp_port: 587
smtp_username: "your-email@gmail.com"
smtp_password: "your-app-password"
from_address: "noreply@example.com"
}
record_apis: [
{
name: "todos"
table_name: "todos"
acl_authenticated: [CREATE, READ, UPDATE, DELETE]
}
]
Logging
TrailBase logs to:
traildepot/logs/trailbase.log - Main application log
traildepot/logs/access.log - HTTP access log
stderr - With --stderr-logging flag
View logs:
# Tail main log
tail -f traildepot/logs/trailbase.log
# View access log
tail -f traildepot/logs/access.log
# Search logs
grep ERROR traildepot/logs/trailbase.log
Debugging
Verbose Logging
# Set log level via environment
export RUST_LOG = debug
trail run
Test Database Queries
# Open database
sqlite3 traildepot/data/main.db
# List tables
.tables
# Describe table
.schema todos
# Query data
SELECT * FROM todos ;
# Check migrations
SELECT * FROM _schema_history ;
Health Check
# Check if server is running
curl http://localhost:4000/_/health
# Output:
{ "status" : "ok" }
Systemd Service
Run TrailBase as a systemd service:
/etc/systemd/system/trailbase.service
[Unit]
Description =TrailBase Server
After =network.target
[Service]
Type =simple
User =trailbase
Group =trailbase
WorkingDirectory =/var/lib/trailbase
Environment = "DATA_DIR=/var/lib/trailbase"
Environment = "PUBLIC_URL=https://example.com"
ExecStart =/usr/local/bin/trail run --address 0.0.0.0:4000
Restart =always
RestartSec =10
[Install]
WantedBy =multi-user.target
Manage the service:
# Enable and start
sudo systemctl enable trailbase
sudo systemctl start trailbase
# Check status
sudo systemctl status trailbase
# View logs
sudo journalctl -u trailbase -f
# Restart
sudo systemctl restart trailbase
Docker
Run TrailBase in Docker:
# Pull image
docker pull trailbase/trailbase:latest
# Run container
docker run -d \
--name trailbase \
-p 4000:4000 \
-v $( pwd ) /traildepot:/data \
-e PUBLIC_URL=http://localhost:4000 \
trailbase/trailbase:latest
# View logs
docker logs -f trailbase
# Execute commands
docker exec trailbase trail admin list
Docker Compose:
version : '3.8'
services :
trailbase :
image : trailbase/trailbase:latest
ports :
- "4000:4000"
volumes :
- ./traildepot:/data
environment :
- DATA_DIR=/data
- PUBLIC_URL=https://example.com
command : run --address 0.0.0.0:4000
restart : unless-stopped
Next Steps
First App Build your first application
Migrations Learn about database migrations
Authentication Manage users and auth
WASM Runtime Extend with WebAssembly
Reference