Development Commands

Development server and tools for local development

Development Commands

The forge dev command provides development tools and server management for local development. It supports hot reload, app discovery, Docker container development, and interactive development workflows.

Main Command

forge dev

Start development server and tools.

forge dev                    # Interactive app selection
forge dev -a api-gateway     # Run specific app
forge dev -a api -p 8080     # Run on specific port
forge dev --watch            # With hot reload (default)
forge dev --docker           # Run inside Docker container
forge dev -d -a api --network forge-net  # Docker with custom network

Flags:

  • -a, --app - App to run
  • -w, --watch - Watch for changes (default: true)
  • -p, --port - Port number
  • -d, --docker - Run inside Docker container
  • --network - Docker network name (requires --docker)

Behavior:

  • If no app is specified, shows an interactive app selector
  • Automatically discovers apps in your project
  • Supports both single-module and multi-module layouts
  • Sets PORT environment variable if specified
  • With --docker, builds a dev image and runs the app in a container with bind-mount hot reload

Subcommands

forge dev list (aliases: ls)

List all available apps in your project.

forge dev list
forge dev ls

Output: Shows a table with app information:

  • Name: App name
  • Type: App type (usually "app")
  • Location: Path to app directory
  • Status: Ready status

Example Output:


 Name         Type  Location         Status 

 api-gateway  app   cmd/api-gateway   Ready
 auth-service app   cmd/auth-service  Ready

forge dev build

Build app for development.

forge dev build -a api-gateway
forge dev build --app auth-service

Flags:

  • -a, --app - App to build (required)

Behavior:

  • Builds the specified app using go build
  • Outputs to bin/<app-name> directory
  • Shows build progress with spinner
  • Displays success/failure status

App Discovery

Forge automatically discovers apps in your project based on the layout:

Single-Module Layout

For single-module projects, Forge scans the cmd/ directory:

my-project/
 cmd/
    api-gateway/
       main.go
    auth-service/
       main.go
    worker/
        main.go
 .forge.yaml

Multi-Module Layout

For multi-module projects, Forge scans the apps/ directory:

my-project/
 apps/
    api-gateway/
       cmd/
           server/
               main.go
    auth-service/
       cmd/
           server/
               main.go
    worker/
        cmd/
            server/
                main.go
 .forge.yaml

Development Features

Hot Reload

Hot reload automatically restarts your application when files change:

forge dev --watch

The file watcher monitors .go files across your project and uses a configurable debounce delay (default: 300ms) to avoid rapid successive restarts. Configure watch behavior in .forge.yaml:

dev:
  hot_reload:
    enabled: true
    delay: 500ms   # debounce delay before restart
  watch:
    enabled: true
    paths:
      - "./apps/**/internal/**/*.go"
      - "./pkg/**/*.go"
      - "./internal/**/*.go"
    exclude:
      - "**/*_test.go"
      - "**/testdata/**"
      - "**/vendor/**"

Port Configuration

Set a custom port for your application:

forge dev -p 3000
forge dev --port 8080

Port precedence:

  1. --port CLI flag (highest priority)
  2. App-level .forge.yaml port (apps/<name>/.forge.yamldev.port)
  3. Application default (no PORT env var set)

Interactive App Selection

When no app is specified, Forge shows an interactive selector:

forge dev

Output:

? Select app to run: 
   api-gateway
    auth-service
    worker

Docker Development Mode

The --docker (or -d) flag runs your app inside a Docker container with bind-mounted source code and hot reload. This ensures your development environment mirrors production and works consistently across machines.

Quick Start

# Run an app in Docker with hot reload
forge dev --docker -a api-gateway

# With port forwarding
forge dev -d -a api-gateway -p 8080

# With a custom Docker network
forge dev -d -a api-gateway --network forge-net

How It Works

When you run forge dev --docker, Forge performs the following steps:

  1. Verify Docker — checks that the docker binary is in PATH and the daemon is running.
  2. Resolve config — merges project-level dev.docker, app-level dev.docker, and CLI flags (highest priority).
  3. Build dev image — uses your custom Dockerfile if configured, otherwise auto-generates a development-optimized Dockerfile.
  4. Run container — starts the container with the project root bind-mounted to /app, port forwarding, and environment variables.
  5. Watch for changes — monitors .go files on the host; on change, restarts the container (docker restart) after a debounce delay.
  6. Stream logs — container stdout/stderr is streamed to your terminal in real time.
  7. Graceful shutdownCtrl+C stops and removes the container.

The container name follows the pattern forge-dev-<app-name> and the image is tagged forge-dev-<app-name>:latest. Any previous container with the same name is automatically removed before starting.

Auto-Generated Dev Dockerfile

When no custom Dockerfile is configured, Forge generates a temporary Dockerfile optimized for development:

# Auto-generated by forge dev --docker
FROM golang:1.25-alpine
RUN apk add --no-cache git
WORKDIR /app
COPY go.mod go.sum* ./
RUN go mod download
# Forge config files
COPY .forge.yaml ./
COPY config/ ./config/
COPY . .
CMD ["go", "run", "./cmd/api-gateway"]

The generator automatically discovers and adds COPY directives for:

  • .forge.yaml / .forge.yml project config
  • config/ directory
  • config.yaml, config.local.yaml runtime configs
  • .env* files
  • Per-app .forge.yaml files in apps/
  • database/ directory (migrations and seeds)

This ensures Forge config files have their own Docker cache layer, so rebuilds after a source change do not re-download Go modules.

Docker Dev Configuration

Configure Docker dev settings at the project level in .forge.yaml:

dev:
  docker:
    image: golang:1.25-alpine       # Base image (default: golang:1.25-alpine)
    dockerfile: ""                   # Custom Dockerfile path (empty = auto-generate)
    network: bridge                  # Docker network (default: bridge)
    platform: linux/amd64            # Target platform (optional)
    volumes:                         # Extra host:container volume mounts
      /tmp/go-cache: /root/.cache/go-build
    env:                             # Extra environment variables
      DEBUG: "true"
      LOG_LEVEL: debug
    build_args:                      # Docker build arguments
      GO_VERSION: "1.25"
FieldTypeDefaultDescription
imagestringgolang:1.25-alpineBase Docker image for the dev container
dockerfilestring"" (auto-generate)Path to a custom Dockerfile for dev
networkstringbridgeDocker network to attach the container to
platformstring""Target platform (e.g., linux/amd64)
volumesmap[string]string{}Extra volumes — key is host path, value is container path
envmap[string]string{}Extra environment variables injected into the container
build_argsmap[string]string{}Docker build arguments passed to docker build

Per-App Docker Configuration

Override Docker settings for individual apps by placing a .forge.yaml in the app's directory:

# apps/api-gateway/.forge.yaml
app:
  name: api-gateway
  type: web

dev:
  port: 8080
  docker:
    image: golang:1.25-bookworm   # Use Debian instead of Alpine
    network: api-network
    env:
      SERVICE_NAME: api-gateway
    volumes:
      ./certs: /app/certs

Config merging follows this priority (highest to lowest):

  1. CLI flags--network overrides everything
  2. App-level apps/<name>/.forge.yamldev.docker
  3. Project-level .forge.yamldev.docker

Maps (volumes, env, build_args) are merged — app-level keys override project-level keys with the same name; unique keys from both levels are preserved.

Custom Dev Dockerfile

For advanced setups, point to your own Dockerfile:

dev:
  docker:
    dockerfile: docker/dev.Dockerfile
# docker/dev.Dockerfile
FROM golang:1.25-bookworm

# Install system dependencies
RUN apt-get update && apt-get install -y \
    protobuf-compiler \
    && rm -rf /var/lib/apt/lists/*

# Install Go tools
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

COPY . .
CMD ["go", "run", "./cmd/api-gateway"]

Docker Networking for Multi-Service Dev

When developing multiple services locally, use a shared Docker network so containers can reach each other by name:

# Create a shared network
docker network create forge-net

# Start each service on the shared network
forge dev -d -a api-gateway    --network forge-net -p 8080
forge dev -d -a auth-service   --network forge-net -p 8081
forge dev -d -a user-service   --network forge-net -p 8082

Or configure the network in .forge.yaml so you don't need the --network flag:

dev:
  docker:
    network: forge-net

Inside the containers, services can reach each other using the container name:

// From api-gateway container, call auth-service
resp, err := http.Get("http://forge-dev-auth-service:8081/verify")

Each forge dev -d command runs in the foreground and streams logs. Open separate terminal windows for each service, or use a process manager like tmux or foreman.

Environment Variables

Forge injects the following environment variables into every Docker dev container automatically:

VariableValueDescription
FORGE_DEVtrueIndicates development mode
FORGE_HOT_RELOADtrueIndicates hot reload is active
FORGE_DOCKERtrueIndicates running inside Docker
PORT<port>Only set if --port flag was provided

Additional variables from dev.docker.env are appended after these defaults.

Project Requirements

Forge Project

The forge dev command requires a Forge project with a .forge.yaml file:

# If not in a Forge project
forge dev
# Error: no .forge.yaml found in current directory or any parent
# This doesn't appear to be a Forge project.
# To initialize a new project, run:
#   forge init

App Structure

Each app must have a main.go file with a main() function:

package main

import (
    "log"
    "github.com/xraph/forge"
)

func main() {
    app := forge.NewApp(forge.AppConfig{
        Name:    "my-app",
        Version: "0.1.0",
    })

    // Register routes
    app.Router().GET("/", func(c forge.Context) error {
        return c.JSON(200, forge.Map{
            "message": "Hello from my-app!",
        })
    })

    // Start server
    if err := app.Run(); err != nil {
        log.Fatal(err)
    }
}

Configuration

Development Configuration

Configure development settings in .forge.yaml:

dev:
  port: 8080
  hot_reload: true
  debug: true
  extensions:
    - auth
    - database

Environment Variables

Set environment variables for development:

export PORT=3000
export DEBUG=true
export LOG_LEVEL=debug

forge dev

Troubleshooting

No Apps Found

If no apps are found:

forge dev
# Warning: No apps found. Create one with: forge generate app

Solution:

forge generate app --name=my-app

App Not Found

If the specified app doesn't exist:

forge dev -a nonexistent-app
# Error: app not found: nonexistent-app

Solution:

# List available apps
forge dev list

# Or create the app
forge generate app --name=nonexistent-app

Build Failures

If app build fails:

forge dev build -a my-app
#  Build failed

Common causes:

  • Missing dependencies
  • Syntax errors in code
  • Missing main.go file

Solution:

# Retry the build
forge dev build -a my-app

# Install dependencies
go mod tidy

# Verify main.go exists
ls cmd/my-app/main.go

Best Practices

  1. Use Interactive Mode — Let Forge discover and select apps automatically.
  2. Set Custom Ports — Use -p flag to avoid port conflicts.
  3. Enable Hot Reload — Watch mode is on by default; configure debounce delay if restarts are too frequent.
  4. Check App Status — Use forge dev list to verify available apps.
  5. Build Before Dev — Use forge dev build to catch build errors early.
  6. Use Docker for Consistency — Use --docker to ensure your dev environment matches production (same OS, same Go version).
  7. Shared Networks — When running multiple services in Docker, use a shared --network so containers can communicate by name.
  8. Cache Go Modules — Mount a volume for the Go module cache to speed up Docker rebuilds:
    dev:
      docker:
        volumes:
          /tmp/forge-gomod: /go/pkg/mod

For more information about code generation, see the Code Generation Commands documentation.

How is this guide?

On this page