CLI Reference
Complete reference for Radish CLI commands and workflows.
Installation
Global Installation
npm install -g radish-cli
Local Development
# From the CLI repo root
npm install
npm link # or: npm install -g .
Check Version
radish-cli --version
Commands
create app
Generate a complete full-stack application (skeleton + datalayer + admin panel + UI layer).
radish-cli create app <name> [options]
Arguments:
<name>- Application name (used for directory, database, cookie prefix)
Options:
| Option | Description | Default |
|---|---|---|
--schema <path> | Path to types blueprint | - |
--app <path> | Path to app blueprint | - |
--roles <path> | Path to roles blueprint | - |
--ui <path> | Path to UI blueprint | - |
--preset <name> | Built-in sample (todo, library) | library |
--stack <name> | Target stack (node, laravel) | node |
--in-place | Generate into current directory instead of creating a subdirectory | false |
--features <list> | Comma-separated features (cms, grants) | - |
--seed | Auto-seed database after generation | false |
--dry | Dry run — show files without writing | false |
Examples:
# Full app with default library preset
radish-cli create app my-app
# From existing blueprints
radish-cli create app my-app --schema ./blueprints/app.types.json --roles ./blueprints/app.roles.json
# Generate into current directory (for existing project folders)
radish-cli create app my-app --in-place
# With CMS and grants features
radish-cli create app my-app --features cms,grants
What gets generated:
- SvelteKit skeleton (package.json, svelte.config.js, Dockerfile, docker-compose.yml, .gitlab-ci.yml)
- Datalayer (contracts, models, repos, services, routes)
- Admin panel (dashboard, user management, entity CRUD)
- Setup route at
/setupfor first-time admin creation - SEO infrastructure (sitemap.xml, robots.txt, llms.txt)
create datalayer
Generate a datalayer from a blueprint.
radish-cli create datalayer <output-path> [options]
Arguments:
<output-path>- Directory to generate code in (e.g.,.,./my-app)
Options:
| Option | Description | Default |
|---|---|---|
--app-name <name> | Friendly app name (for DB & UI) | Directory name |
--preset <name> | Built-in sample (todo, library) | library |
--schema <path> | Path to custom types blueprint | - |
--db-url <url> | Database URL for seeding | mongodb://localhost:27017 |
--stack <name> | Target stack (node, laravel) | node |
--features <list> | Comma-separated features (cms, grants) | - |
--seed | Auto-seed database after generation | false |
--dry | Dry run - show files without writing | false |
Examples:
# Basic generation with library preset
radish-cli create datalayer ./my-app
# With custom schema
radish-cli create datalayer . --schema ./blueprints/app.types.json
# With database seeding
radish-cli create datalayer . --seed --db-url mongodb://localhost:27017/mydb
# Dry run to preview files
radish-cli create datalayer . --dry
console
Launch the interactive datalayer inspector.
radish-cli console <app-path> [options]
Arguments:
<app-path>- Path to Radish-generated app (default:.)
Options:
| Option | Description | Default |
|---|---|---|
-p, --port <port> | Port to run console on | 5173 |
--build | Build for production instead of dev | false |
Examples:
# Launch console for current directory
radish-cli console .
# Launch on custom port
radish-cli console ./my-app --port 3000
# Build for production
radish-cli console . --build
verify
Verify that generated code matches the current blueprint.
radish-cli verify [app-path] [options]
Arguments:
[app-path]- Path to app directory (default:.)
Options:
| Option | Description | Default |
|---|---|---|
--verbose | Show detailed hash comparison | false |
Exit codes:
0- Generated code matches blueprint1- Generated code out of sync with blueprint
Examples:
# Basic verification
radish-cli verify .
# Verbose output with hash details
radish-cli verify . --verbose
# Use in CI/CD
radish-cli verify || exit 1
info
Display manifest information about generated code.
radish-cli info [app-path] [options]
Arguments:
[app-path]- Path to app directory (default:.)
Options:
| Option | Description | Default |
|---|---|---|
--json | Output as JSON | false |
Examples:
# Human-readable info
radish-cli info .
# JSON output for scripting
radish-cli info . --json
# Extract specific fields
radish-cli info . --json | jq '.radishVersion'
clean
Remove all Radish-generated code and configuration.
radish-cli clean [app-path] [options]
Arguments:
[app-path]- Path to app directory (default:.)
Options:
| Option | Description | Default |
|---|---|---|
--dry-run | Show what would be removed without removing | false |
--force | Skip confirmation prompts | false |
Examples:
# Clean with confirmation
radish-cli clean .
# Dry run to see what would be removed
radish-cli clean . --dry-run
# Force clean without prompts
radish-cli clean . --force
deploy init
Provision a new application on Coolify for deployment.
radish deploy init [app-path] [options]
Arguments:
[app-path]- Path to app directory (default:.)
Options (non-interactive / CI mode):
| Option | Description | Default |
|---|---|---|
--name <name> | App name on Coolify | From package.json |
--server <name> | Coolify server name | - |
--project <name> | Coolify project name | - |
--env <name> | Coolify environment name | production |
--domain <domain> | App domain | - |
--registry <url> | Docker registry URL | - |
--image <image> | Docker image name | - |
Interactive mode (default): Prompts for server, project, environment, domain, and registry settings using your configured Coolify instances.
Non-interactive mode: Pass all required flags for CI/scripting use.
Prerequisites:
cfyCLI installed (npm install -g @abeedoo/cfy)- At least one Coolify instance configured (
cfy setup)
Examples:
# Interactive provisioning
radish deploy init
# Non-interactive for CI
radish deploy init --name my-app --server prod --project apps --domain my-app.example.com
# From a specific app directory
radish deploy init ./my-app
What it does:
- Creates a Docker image app on Coolify
- Sets environment variables (MONGO_URL, SESSION_SECRET, etc.)
- Configures health checks
- Saves target config to
.radish.deploy.json - Auto-generates
JWT_SECRETandRADISH_ENCRYPTION_KEY
Post-init steps (displayed after completion):
- Add Coolify's deploy key to your GitLab/GitHub repo
- Set
CI_REGISTRY,CI_REGISTRY_USER,CI_REGISTRY_PASSWORDin CI variables - Tag and push to trigger the first build
seed
Seed the database with roles, an admin user, and sample data.
radish-cli seed [app-path] [options]
Arguments:
[app-path]- Path to app directory (default:.)
Options:
| Option | Description | Default |
|---|---|---|
--sync-roles | Sync roles only (no admin user or sample data) | false |
--db-url <url> | MongoDB connection string | From .env |
Behavior notes:
- Role seeding populates permissions from the blueprint's
roles.json - When a
/setuproute exists (generated bycreate app), admin user creation is skipped — the setup wizard handles first-time admin onboarding instead - Reads
MONGO_URLfrom the app's.envfile if--db-urlis not specified
Examples:
# Full seed (roles + admin + sample data)
radish-cli seed .
# Sync roles only after blueprint changes
radish-cli seed --sync-roles
# With explicit database URL
radish-cli seed . --db-url mongodb://localhost:27017/myapp
Workflows
Initial Setup
Create your first Radish project:
# 1. Create project directory
mkdir my-app && cd my-app
# 2. Create blueprint
mkdir blueprints
cat > blueprints/app.types.json << 'EOF'
{
"version": 1,
"defaults": {
"owned": true,
"timestamps": true
},
"entities": {
"Task": {
"plural": "tasks",
"fields": {
"title": { "type": "string", "required": true },
"done": { "type": "boolean", "default": false }
},
"filters": ["done"]
}
}
}
EOF
# 3. Generate datalayer
radish-cli create datalayer . --schema blueprints/app.types.json
# 4. Launch console to explore
radish-cli console .
Regeneration
Regenerate after blueprint changes:
# 1. Edit blueprint
vim blueprints/app.types.json
# 2. Regenerate (same command as initial generation)
radish-cli create datalayer . --schema blueprints/app.types.json
# 3. Review changes
git diff .radish/
# 4. Verify manifest changes
cat .radish/MANIFEST.json | jq '.blueprints.types.hash'
# 5. Test your app
npm test
# 6. Commit blueprint + generated code together
git add blueprints/ .radish/
git commit -m "feat: add description field to Task"
Blueprint Verification
Check if generated code matches your current blueprint:
# View blueprint hash from manifest
cat .radish/MANIFEST.json | jq '.blueprints.types.hash'
# Output: "sha256:89f21a4b2c3d4e5f"
# Manually compute hash of current blueprint
cat blueprints/app.types.json | sha256sum | head -c 16
# Compare the hashes - they should match
If hashes don't match: Generated code is out of sync with blueprint. Regenerate:
radish-cli create datalayer . --schema blueprints/app.types.json
Automated verification commands:
# Verify generated code matches blueprint
radish-cli verify # Exit 0 if match, exit 1 if mismatch
radish-cli verify --verbose # Show detailed hash comparison
# Display manifest information
radish-cli info # Human-readable format
radish-cli info --json # Machine-readable JSON output
Future CLI commands (planned):
radish-cli compare staging # Compare local vs deployed manifests
Version Management
Check Generated Version
View generation metadata and blueprint hash:
# View top-level manifest
cat .radish/MANIFEST.json
# View datalayer-specific manifest
cat .radish/lib/datalayer/MANIFEST.json
Top-level manifest (.radish/MANIFEST.json):
{
"$schema": "https://radish-cli.dev/schemas/manifest.v1.json",
"manifestVersion": "1.0",
"radishVersion": "0.6.0",
"projectName": "my-app",
"generatedAt": "2026-03-11T10:30:00.000Z",
"blueprints": {
"types": {
"path": "blueprints/app.types.json",
"hash": "sha256:89f21a4b2c3d4e5f",
"lastModified": "2026-03-11T09:15:00.000Z"
}
},
"layers": {
"datalayer": {
"enabled": true,
"manifestPath": "lib/datalayer/MANIFEST.json",
"version": "1.0.0"
}
}
}
Datalayer manifest (.radish/lib/datalayer/MANIFEST.json):
{
"$schema": "https://radish-cli.dev/schemas/datalayer-manifest.v1.json",
"manifestVersion": "1.0",
"layer": "datalayer",
"radishVersion": "0.6.0",
"blueprint": {
"path": "blueprints/app.types.json",
"hash": "sha256:89f21a4b2c3d4e5f",
"entities": 12,
"builtinEntities": 3,
"customEntities": 9
},
"entities": [
{
"name": "Task",
"type": "custom",
"builtin": false,
"fields": 5,
"relationships": ["User"],
"features": {
"versioning": false,
"filtering": true,
"population": true
}
}
],
"generated": {
"contracts": { "files": 18 },
"models": { "files": 12 },
"services": { "files": 14 }
}
}
Use cases:
- Check CLI version used for generation
- Verify blueprint hash matches current blueprint
- See entity counts and generated file counts
- Debug regeneration issues
- Compare manifests across environments
Update CLI Version
# 1. Update CLI
npm update -g radish-cli
# 2. Check new version
radish-cli --version
# 3. Read changelog
cat node_modules/radish-cli/CHANGELOG.md
# 4. Regenerate
radish-cli create datalayer . --schema blueprints/app.types.json
# 5. Review changes
git diff .radish/
# 6. Commit
git commit -m "chore: regenerate with radish-cli v0.6.0"
Semantic Versioning
Radish CLI follows semantic versioning (MAJOR.MINOR.PATCH):
| Version Change | Risk | Description | Action Required |
|---|---|---|---|
| MAJOR (0.x → 1.x) | 🔴 High | Breaking changes in generated API | Review CHANGELOG, update code, test thoroughly |
| MINOR (0.6.x → 0.7.x) | 🟡 Low-Medium | New features, non-breaking | Safe to regenerate, optional feature adoption |
| PATCH (0.6.0 → 0.6.1) | 🟢 Low | Bug fixes only | Safe to regenerate immediately |
Schema Migrations
Safe Changes (No Migration Required)
These changes are backward-compatible:
- ✅ Adding optional fields
- ✅ Adding new entities
- ✅ Changing field labels/descriptions
- ✅ Adding indexes
{
"Task": {
"fields": {
"title": { "type": "string", "required": true },
"description": { "type": "string", "optional": true }
}
}
}
Action: Regenerate and deploy immediately.
Breaking Changes (Migration Required)
These changes require database migration:
- ⚠️ Adding required fields
- ⚠️ Changing field types
- ⚠️ Removing fields
- ⚠️ Renaming fields
{
"Task": {
"fields": {
"title": { "type": "string", "required": true },
"priority": { "type": "int", "required": true }
}
}
}
Migration Workflow:
# 1. Backup database
mongodump --db myapp --out ./backup-$(date +%Y%m%d)
# 2. Write migration script
cat > scripts/migrate-add-priority.js << 'EOF'
const { MongoClient } = require('mongodb');
async function migrate() {
const client = new MongoClient(process.env.MONGO_URL);
await client.connect();
const db = client.db();
const tasks = db.collection('tasks');
// Add required field with default value
await tasks.updateMany(
{ priority: { $exists: false } },
{ $set: { priority: 1 } }
);
console.log('Migration complete');
await client.close();
}
migrate();
EOF
# 3. Test migration on backup
mongorestore backup/
MONGO_URL=mongodb://localhost:27017/myapp_test node scripts/migrate-add-priority.js
# 4. Update blueprint
vim blueprints/app.types.json
# 5. Regenerate
radish-cli create datalayer . --schema blueprints/app.types.json
# 6. Test thoroughly
npm test
# 7. Deploy migration + code together
Migration Decision Matrix
| Change | DB Migration? | Code Changes? | Example |
|---|---|---|---|
| Add optional field | ❌ No | ❌ No | bio: { optional: true } |
| Add required field | ✅ Yes | 🟡 Maybe | priority: { required: true } |
| Remove field | 🟡 Optional | ❌ No | Delete from JSON |
| Rename field | ✅ Yes | ✅ Yes | Copy data to new field |
| Change type | ✅ Yes | ✅ Yes | string → int |
| Add entity | ❌ No | ❌ No | New entity in JSON |
| Add index | ❌ No | ❌ No | Auto-created |
Troubleshooting
"Cannot find module" after regeneration
Cause: Package structure changed or dependencies not installed.
Solution:
# Reinstall dependencies in generated packages
cd .radish/lib/datalayer/contracts && npm install
cd ../server && npm install
Tests failing after regeneration
Cause: Breaking change in generated API.
Solution:
- Review CHANGELOG for breaking changes
- Update test code to use new APIs
- Check for schema naming convention changes
Database validation errors
Cause: Schema changed but database has old data.
Solution:
- Run migration script before deploying
- Ensure all required fields have values
- Check field type compatibility
"File already exists" error
Cause: Generating to wrong directory or permissions issue.
Solution:
- Verify output path is correct
- Check directory permissions
- Use
--dryflag to preview first
Best Practices
1. Commit Blueprint + Generated Code Together
git add blueprints/ .radish/
git commit -m "feat: add Task entity"
Makes code review easier and keeps blueprint changes visible alongside generated changes.
2. Test After Every Regeneration
npm test # Run full test suite
Even "safe" changes can have unexpected effects.
3. Use Version Control
# Never regenerate without committing first
git status
git commit -m "checkpoint before regeneration"
radish-cli create datalayer .
Easy rollback if regeneration causes issues.
4. Pin CLI Version in CI
{
"name": "Install Radish CLI",
"run": "npm install -g radish-cli@0.6.0"
}
Ensures consistent builds across environments.
5. Monitor for Updates
- Watch Radish CLI releases on GitHub
- Subscribe to changelog notifications
- Update regularly for bug fixes
Dependencies
cfy CLI
The deploy init command requires cfy (@abeedoo/cfy) — a Coolify v4 API client that manages Coolify instances.
npm install -g @abeedoo/cfy
cfy setup # Configure your first Coolify instance
Instance credentials are stored at ~/.coolify-cli/config (per-user, not committed).
Environment Variables
| Variable | Description | Default |
|---|---|---|
RADISH_APP_PATH | Path to app (console command) | Current directory |
PORT | Console port | 5173 |
MONGO_URL | Database connection string | mongodb://localhost:27017 |
SESSION_SECRET | Secret for signing session cookies (preferred) | - |
RADISH_ENCRYPTION_KEY | Fallback secret when SESSION_SECRET is not set | - |
RADISH_HUB_URL | Hub URL for telemetry reporting | - |
RADISH_HUB_TOKEN | Hub auth token for telemetry push | - |
Generated Files
After create app
A full-stack application includes all of the below:
my-app/
├── package.json # App dependencies
├── svelte.config.js # Mode-aware path aliases (integrated vs library)
├── Dockerfile # Debian slim base, node healthcheck
├── docker-compose.yml # expose (not ports), pull_policy: always
├── .gitlab-ci.yml # Kaniko build, CI_REGISTRY vars, deploy trigger
├── .env / .env.example # Environment configuration
├── src/
│ ├── hooks.server.ts # sequence(telemetry, rateLimit, idempotency, auth)
│ ├── routes/
│ │ ├── setup/ # First-run admin creation wizard
│ │ ├── (auth)/ # Login, register (centered layout)
│ │ ├── (public)/ # Public pages (auth optional)
│ │ ├── (app)/ # Authenticated pages (redirect to login)
│ │ ├── admin/ # Admin panel (dashboard, users, entities)
│ │ ├── sitemap.xml/ # Dynamic sitemap
│ │ └── robots.txt/ # Dynamic robots.txt
│ └── lib/
│ └── datalayer/ # Generated datalayer (see below)
└── blueprints/ # Source blueprints
After create datalayer
The datalayer package (at .radish/lib/datalayer/ in library mode, or src/lib/ in integrated mode):
datalayer/
├── MANIFEST.json # Datalayer-specific metadata
├── package.json # @generated/datalayer package
├── contracts/ # Zod schemas & TypeScript types
│ ├── common.ts
│ ├── {entity}.ts
│ ├── index.ts
│ └── metadata/ # Field metadata for runtime introspection
├── core/ # Core infrastructure
│ ├── auth/ # Authentication (signed sessions, guards)
│ ├── db/ # Database connection
│ ├── middleware/ # Rate limiting, idempotency
│ ├── models/ # MongoDB models
│ ├── repos/ # Data access layer
│ └── seeds/ # Database seeders
├── telemetry/ # Observability (always-on)
│ ├── adapters/ # ConsoleAdapter, MultiAdapter
│ ├── tracked-fetch.ts # Instrumented fetch for external APIs
│ ├── hub-reporter.ts # Background push to Radish Hub
│ ├── correlation.ts # Correlation ID management
│ ├── logger.ts # Structured logger
│ └── middleware.ts # Request telemetry
├── routes/ # HTTP API routes (SvelteKit)
│ └── api/v1/ # Versioned API endpoints
├── services/ # Business logic with permissions
└── docs/ # App-specific generated documentation
├── API.md # Complete API reference
├── services.md # Service layer docs
├── types.md # TypeScript types
├── roles.md # Auth & permissions
├── AI_CONTEXT.md # AI-friendly summary
└── openapi.json # OpenAPI 3.0 spec
Key files:
- MANIFEST.json files - Track blueprint hashes and generation metadata
- package.json - Self-contained dependencies for generated code
- contracts/ - Type-safe schemas and types for your entities
- core/ - Core infrastructure (models, repos, auth, db)
- services/ - Business logic with permissions
- routes/ - HTTP API routes
- docs/ - Auto-generated API documentation
Next Steps
- Blueprint Reference - Learn blueprint syntax
- [Generated Code]../datalayer/index.md) - Understand what gets generated
- Getting Started - Step-by-step tutorial