Varel CLI Reference

The Varel Command Line Interface (CLI) provides powerful commands for scaffolding, database management, and project creation. This comprehensive reference covers all CLI commands and their usage.

Table of Contents


Installation

Step 1: Compile Varel CLI

# Clone Varel repository
git clone https://github.com/leafscale/varel.git
cd varel

# Compile CLI in production mode
v -prod varel

# This creates the 'varel' executable (2-3MB)

Step 2: Install Globally

# Create symlink to make 'varel' available globally
./varel symlink

# Output: ✓ Symlink created: /usr/local/bin/varel

# Verify installation
varel version
# Output: Varel version 0.1.0

Step 3: Verify

# View all available commands
varel --help

# Output shows all commands:
# - new, init, generate, db, user, symlink, version, help

Global Commands

version

Show Varel version information.

varel version

# Output:
# Varel version 0.1.0
# V compiler: 7e933328b6268cfc37d4d9734f03638193040c83

help

Display help information.

varel help
# or
varel --help

# Shows:
# - Usage information
# - All available commands
# - Examples
# - Documentation links

Create symlink in /usr/local/bin for global access.

./varel symlink

# Creates: /usr/local/bin/varel -> /path/to/varel
# Requires: sudo permissions

Project Commands

new

Create a new Varel application with complete project structure.

varel new <project_name>

Example:

varel new myshop

# Output:
# Creating new Varel project: myshop
#
# Initializing Varel project in /home/user/myshop...
#   Created directory structure
#   Created main.v
#   Created v.mod
#   Created config/config.toml
#   Created controllers/home_controller.v
#   Created controllers/api_controller.v
#   Created README.md
#   Created PROJECT_STRUCTURE.md
#
# ✓ Project myshop created successfully!
#
# Get started:
#   cd myshop
#   v run main.v
#
# Visit: http://localhost:8080

What Gets Created:

  • main.v - Application entry point with routes
  • v.mod - V module definition
  • config/config.toml - Application configuration
  • controllers/ - Home and API controllers
  • models/ - Database models directory
  • views/ - VeeMarker templates directory
  • middleware/ - Custom middleware directory
  • db/migrations/ - Database migrations
  • db/seeds/ - Seed data
  • public/ - Static files (CSS, JS, images)
  • storage/ - Logs and uploads
  • tests/ - Unit and integration tests

Next Steps:

cd myshop
v run main.v
# Visit http://localhost:8080

init

Initialize Varel in an existing directory.

cd existing_project
varel init

# Creates same structure as 'new' but in current directory
# Prompts before overwriting existing files

Use Case: Convert existing V project to Varel application.


Scaffolding Commands

generate scaffold

Generate a complete RESTful resource (controller, model, views, migrations, tests).

varel generate scaffold <ResourceName> <field>:<type> [<field>:<type> ...]

Supported Field Types:

Type SQL Type Description Example
string VARCHAR(255) Short text name:string
text TEXT Long text, unlimited description:text
int INTEGER Whole number stock:int
i64 BIGINT Large integer user_id:i64
decimal DECIMAL(10,2) Money/prices price:decimal
float REAL Floating point rating:float
bool BOOLEAN True/false published:bool
date DATE Date only birthday:date
datetime TIMESTAMP Date and time created_at:datetime
timestamp TIMESTAMP Alias for datetime updated_at:timestamp

Example:

varel generate scaffold Product name:string price:decimal description:text stock:int published:bool

# Generates:
#
# ✓ Created controllers/products_controller.v (with all 7 RESTful actions)
# ✓ Created models/product.v (with CRUD methods)
# ✓ Created views/products/index.html (list view)
# ✓ Created views/products/show.html (detail view)
# ✓ Created views/products/new.html (create form)
# ✓ Created views/products/edit.html (edit form)
# ✓ Created db/migrations/20251013123045_create_products.up.sql
# ✓ Created db/migrations/20251013123045_create_products.down.sql
# ✓ Created tests/controllers/products_controller_test.v
#
# ✓ Scaffold generated successfully!
#
# Next steps:
#   1. varel db migrate
#   2. Add routes to main.v
#   3. Visit http://localhost:8080/products

Using Route Prefixes:

The --prefix flag allows you to generate scaffolds for routes under a specific path prefix (e.g., admin sections):

varel generate scaffold User email:string role:string --prefix /admin

# Generates resources for /admin/users routes
# All generated URLs, redirects, and route comments use /admin prefix:
#   - GET    /admin/users      (index)
#   - GET    /admin/users/new  (new)
#   - POST   /admin/users      (create)
#   - GET    /admin/users/:id  (show)
#   - GET    /admin/users/:id/edit (edit)
#   - PUT    /admin/users/:id  (update)
#   - DELETE /admin/users/:id  (destroy)

Prefix Examples:

# Admin panel resources
varel generate scaffold User email:string --prefix /admin
varel generate scaffold Product name:string price:f64 --prefix /admin

# API resources
varel generate scaffold Article title:string body:text --prefix /api/v1

# Dashboard resources
varel generate scaffold Widget name:string --prefix /dashboard

What Gets Prefixed:

When using --prefix, all generated code uses the prefix:

  1. Views - All links and form actions include prefix

    • <a href="/admin/users">
    • <form action="/admin/users">
  2. Controllers - All redirects use prefix

    • ctx.redirect_temporary('/admin/users/' + id)
  3. Tests - All test requests use prefix

    • app.get('/admin/users')
    • app.post('/admin/users', data)
  4. Route Registration Comments - Show correct routes

    • // app.get('/admin/users', ...)

Registering Prefixed Routes:

After generating with --prefix, register routes in main.v:

import controllers

mut user_ctrl := controllers.UserController{}

// Register admin routes with prefix
app.get('/admin/users', fn [user_ctrl] (mut ctx http.Context) http.Response {
    return user_ctrl.index(mut ctx)
})!
app.get('/admin/users/new', fn [user_ctrl] (mut ctx http.Context) http.Response {
    return user_ctrl.new(mut ctx)
})!
app.post('/admin/users', fn [user_ctrl] (mut ctx http.Context) http.Response {
    return user_ctrl.create(mut ctx)
})!
// ... other routes

Complete Example with Multiple Types:

varel generate scaffold BlogPost \
  title:string \
  slug:string \
  body:text \
  excerpt:text \
  published:bool \
  view_count:int \
  rating:float \
  published_at:datetime \
  author_id:i64

What Each File Contains:

  1. Controller (controllers/products_controller.v)

    • index - List all products
    • show - Show single product
    • new - Show create form
    • create - Handle form submission
    • edit - Show edit form
    • update - Handle update submission
    • destroy - Delete product
  2. Model (models/product.v)

    • Struct definition with all fields
    • create() - Insert new record
    • find() - Find by ID
    • all() - Get all records
    • update() - Update record
    • delete() - Delete record
  3. Views (views/products/)

    • index.html - Table with all products
    • show.html - Product details
    • new.html - Creation form with validation
    • edit.html - Edit form with current values
  4. Migrations (db/migrations/)

    • .up.sql - CREATE TABLE with all fields
    • .down.sql - DROP TABLE (for rollback)
  5. Tests (tests/controllers/)

    • Tests for all 7 actions
    • Database transaction rollback

generate migration

Generate a blank database migration.

varel generate migration <migration_name>

Example:

varel generate migration add_featured_to_products

# Output:
# ✓ Created db/migrations/20251013124530_add_featured_to_products.up.sql
# ✓ Created db/migrations/20251013124530_add_featured_to_products.down.sql
#
# Edit the migration files and run: varel db migrate

Generated Files:

db/migrations/20251013124530_add_featured_to_products.up.sql:

-- Write your UP migration here
-- Example: ALTER TABLE products ADD COLUMN featured BOOLEAN DEFAULT false;

db/migrations/20251013124530_add_featured_to_products.down.sql:

-- Write your DOWN migration here
-- Example: ALTER TABLE products DROP COLUMN featured;

Common Migration Patterns:

-- Add column
ALTER TABLE products ADD COLUMN featured BOOLEAN DEFAULT false;

-- Add index
CREATE INDEX idx_products_featured ON products(featured);

-- Add foreign key
ALTER TABLE orders ADD CONSTRAINT fk_orders_user_id
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;

-- Rename column
ALTER TABLE products RENAME COLUMN price TO unit_price;

-- Change column type
ALTER TABLE products ALTER COLUMN stock TYPE BIGINT;

-- Add unique constraint
ALTER TABLE users ADD CONSTRAINT unique_users_email UNIQUE (email);

Database Commands

db create

Create the database specified in config/config.toml.

varel db create

# Output:
# Creating database: myapp_development
# ✓ Database created successfully!

Configuration (config/config.toml):

[database]
host = "localhost"
port = 5432
database = "myapp_development"
user = "postgres"
password = ""

db migrate

Run all pending database migrations.

varel db migrate

# Output:
# Running migrations...
#   ✓ 20251013120000_create_users.up.sql
#   ✓ 20251013121000_create_products.up.sql
#   ✓ 20251013122000_create_reviews.up.sql
# ✓ Migrations complete! (3 applied)

Migration Tracking:

Varel tracks applied migrations in a schema_migrations table:

SELECT * FROM schema_migrations;
-- version                             | applied_at
-- ----------------------------------- | ------------------------
-- 20251013120000_create_users        | 2025-10-13 12:05:23
-- 20251013121000_create_products     | 2025-10-13 12:05:24
-- 20251013122000_create_reviews      | 2025-10-13 12:05:25

db rollback

Rollback the last applied migration.

varel db rollback

# Output:
# Rolling back last migration...
#   ✓ 20251013122000_create_reviews.down.sql
# ✓ Rollback complete!

Note: Only rolls back ONE migration at a time. Run multiple times to rollback multiple migrations.

db status

Show migration status (applied vs pending).

varel db status

# Output:
# Migration Status:
#   [x] 20251013120000_create_users.up.sql (applied)
#   [x] 20251013121000_create_products.up.sql (applied)
#   [ ] 20251013122000_create_reviews.up.sql (pending)
#   [ ] 20251013123000_add_featured_to_products.up.sql (pending)
#
# Applied: 2
# Pending: 2

db drop

Drop the database (destructive!).

varel db drop

# Prompts for confirmation:
# WARNING: This will permanently delete the database 'myapp_development'
# Are you sure? (yes/no): yes
#
# Dropping database: myapp_development
# ✓ Database dropped

Use Case: Clean up test database or start fresh.


User Management

user create

Create a new user with bcrypt-hashed password.

varel user create <username> <password>

Example:

varel user create admin mySecurePassword123

# Output:
# Creating user: admin
# ✓ User created successfully!
#   Username: admin
#   Password hash: $2a$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5GyYIr9OQvL2u
#   Stored in: config/users.toml

Storage (config/users.toml):

[[users]]
username = "admin"
password_hash = "$2a$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5GyYIr9OQvL2u"
roles = ["admin"]
created_at = "2025-10-13T12:30:45Z"

user list

List all users from config/users.toml.

varel user list

# Output:
# Users:
#   - admin (roles: admin)
#   - editor (roles: editor, user)
#   - viewer (roles: user)
#
# Total: 3 users

user delete

Delete a user from config/users.toml.

varel user delete <username>

# Example:
varel user delete editor

# Output:
# Deleting user: editor
# ✓ User deleted successfully!

Secret Management

Varel provides cryptographically secure secret key generation for session encryption and other security features.

secret generate

Generate a random secret key for session encryption or other security purposes.

Basic Usage:

# Generate 64-character secret (32 bytes, default)
varel secret generate

# Output: 9e40bd70d1a083bef588513f9fe2e4569e9e401eb181ea0d348da55f543337c2

With Custom Length:

# Generate 128-character secret (64 bytes)
varel secret generate --length 64

# Output: 34899e24d2ad0aa66fbb2d45da12abf372af406e1f9c087aa9dfc9c6757240e6afe9c68551b56580b686d37842193224fdb91be16be66826868b3d7f512810c0

Replace Secret in config.toml:

# Generate and automatically update config/config.toml
varel secret generate --replace

# Output:
# ✓ Updated secret_key in config/config.toml
#   New secret: 05fc043d8f61efbc0aaa9f153f23623a9bc7bd83d29af82f182edc5c147cb401

Options:

  • --length, -l <bytes>: Length in bytes (default: 32, produces 64 hex characters)
  • --replace, -r: Replace secret_key in config/config.toml automatically

Security Features:

  • Uses crypto.rand for cryptographically secure random number generation
  • Minimum 16 bytes (32 characters) enforced
  • Hex-encoded output (safe for TOML config files)
  • Default 32 bytes provides 256 bits of entropy

Use Cases:

  1. Session Secret Rotation: Periodically rotate session secrets in production
  2. New Environments: Generate unique secrets for staging/production
  3. Security Incident Response: Quickly generate new secrets after compromise
  4. Development: Test with different secret keys

Best Practices:

  • Development: Auto-generated secret during varel new is sufficient
  • Production: Use --replace to generate a unique secret before deployment
  • Secret Rotation: Regularly rotate secrets (e.g., every 90 days)
  • Never Commit Secrets: Add config/config.toml to .gitignore or use environment variables

Example Workflow:

# Before deploying to production
cd myapp
varel secret generate --replace

# Verify the new secret
grep secret_key config/config.toml
# secret_key = "92d7e1d6cd4158fd92c58f717871f32ff88b11a2e41644de20f9e5abadd62302"

# Deploy to production
git add config/config.toml
git commit -m "Rotate session secret for production"
git push production master

Note: New projects created with varel new automatically generate a unique secret key. You only need to use this command for:

  • Rotating secrets in existing projects
  • Generating additional secrets for other purposes
  • Creating environment-specific secrets

Complete Workflows

Workflow 1: New Project from Scratch

# 1. Create new project
varel new blog
cd blog

# 2. Create database
varel db create

# 3. Generate Post resource
varel generate scaffold Post title:string body:text published:bool author:string

# 4. Run migrations
varel db migrate

# 5. Create admin user
varel user create admin admin123

# 6. Start application
v run main.v

# 7. Visit http://localhost:8080/posts

Workflow 2: Add Feature to Existing Project

# 1. Generate new resource
varel generate scaffold Comment post_id:i64 author:string body:text

# 2. Run migration
varel db migrate

# 3. Add routes in main.v
# (Register comments controller)

# 4. Test
v run main.v

Workflow 3: Database Schema Changes

# 1. Generate migration
varel generate migration add_email_to_users

# 2. Edit migration file
# db/migrations/YYYYMMDDHHMMSS_add_email_to_users.up.sql:
# ALTER TABLE users ADD COLUMN email VARCHAR(255) UNIQUE;

# db/migrations/YYYYMMDDHHMMSS_add_email_to_users.down.sql:
# ALTER TABLE users DROP COLUMN email;

# 3. Run migration
varel db migrate

# 4. Check status
varel db status

# 5. If needed, rollback
varel db rollback

Workflow 4: Clean Development Database

# Manually reset database (drop + create + migrate)
varel db drop
varel db create
varel db migrate

Tips & Best Practices

Scaffolding

DO:

  • ✅ Use singular, PascalCase names: Product, BlogPost, UserProfile
  • ✅ Keep initial scaffolds simple, add complexity via migrations
  • ✅ Review generated code before using
  • ✅ Customize templates to fit your needs

DON'T:

  • ❌ Use plural names: Products (use Product)
  • ❌ Use snake_case: blog_post (use BlogPost)
  • ❌ Generate with too many fields initially (add via migrations)

Migrations

DO:

  • ✅ Test migrations on development database first
  • ✅ Write reversible migrations (proper .down.sql)
  • ✅ Use transactions (PostgreSQL does this automatically for DDL)
  • ✅ Add indexes for foreign keys and frequently queried columns
  • ✅ Check status before migrating: varel db status

DON'T:

  • ❌ Edit applied migrations (create new migration instead)
  • ❌ Skip writing .down.sql files
  • ❌ Run migrations directly on production without testing
  • ❌ Ignore migration errors

Database Commands

DO:

  • ✅ Use varel db status frequently to check state
  • ✅ Back up production database before migrations
  • ✅ Use varel db drop and varel db create freely in development
  • ✅ Version control your migrations

DON'T:

  • ❌ Use varel db drop on production without backups
  • ❌ Run migrations without reviewing SQL first
  • ❌ Forget to commit migration files to git

User Management

DO:

  • ✅ Use strong passwords (minimum 12 characters)
  • ✅ Limit number of admin accounts
  • ✅ Rotate passwords regularly
  • ✅ Store config/users.toml securely (add to .gitignore)

DON'T:

  • ❌ Commit passwords to git
  • ❌ Use simple passwords like "password" or "admin123"
  • ❌ Share admin credentials

Troubleshooting

Command Not Found

Problem: varel: command not found

Solutions:

# 1. Check if symlink exists
ls -la /usr/local/bin/varel

# 2. Recreate symlink
cd /path/to/varel
./varel symlink

# 3. Add to PATH manually
export PATH=$PATH:/path/to/varel
# Add to ~/.bashrc or ~/.zshrc for persistence

Database Connection Errors

Problem: Failed to connect to database

Solutions:

# 1. Check PostgreSQL is running
systemctl status postgresql
# or
pg_isready

# 2. Verify config/config.toml settings
cat config/config.toml

# 3. Test connection manually
psql -h localhost -U postgres -d myapp_development

# 4. Check environment variables
echo $DB_HOST $DB_PORT $DB_NAME $DB_USER $DB_PASSWORD

Migration Fails

Problem: Migration fails with SQL error

Solutions:

# 1. Check the SQL syntax in migration file
cat db/migrations/YYYYMMDDHHMMSS_migration_name.up.sql

# 2. Test SQL manually
psql -h localhost -U postgres -d myapp_development
# Run the SQL from migration file

# 3. Fix the migration file
# Edit db/migrations/YYYYMMDDHHMMSS_migration_name.up.sql

# 4. Rollback if already applied
varel db rollback

# 5. Re-run migration
varel db migrate

Scaffold Generates Invalid Code

Problem: Generated code doesn't compile

Solutions:

# 1. Check field types are supported
varel generate scaffold --help

# 2. Use proper naming (singular, PascalCase)
varel generate scaffold Product  # ✅ Correct
varel generate scaffold products # ❌ Wrong

# 3. Report bug if it's a framework issue
# GitHub: https://github.com/leafscale/varel/issues

Permission Denied

Problem: Permission denied when creating symlink

Solutions:

# 1. Use sudo
sudo ./varel symlink

# 2. Or install to local bin (no sudo required)
mkdir -p ~/.local/bin
cp varel ~/.local/bin/
# Add to PATH: export PATH=$PATH:~/.local/bin

Environment Variables

Override config values with environment variables:

# Database
export DB_HOST=localhost
export DB_PORT=5432
export DB_NAME=myapp_production
export DB_USER=postgres
export DB_PASSWORD=secure_password

# Server
export PORT=8080
export VAREL_ENV=production

# Run with environment variables
varel db migrate

See Also


Getting Help

  • CLI Help: varel --help or varel <command> --help
  • Documentation: See docs/guides/ directory
  • Examples: Check examples/ directory
  • Issues: Report bugs at https://github.com/leafscale/varel/issues
  • Discord: Join V language Discord for support

Varel CLI makes building web applications fast and enjoyable! 🚀