Skip to content

Local Development

This guide covers building Ironflow from source, running the development server, and developing SDKs locally.

Prerequisites

  • Go 1.26+ (no CGO required)
  • Node.js 24+ and pnpm
  • Buf CLI (for protobuf generation) - Install Guide
  • Docker (required for PostgreSQL and integration tests)

Building from Source

Clone the repository and build the binary:

Terminal window
git clone https://github.com/sahina/ironflow.git
cd ironflow
make all

make all runs the full pipeline: downloads dependencies, generates protobuf code, builds the React dashboard, embeds it into the Go binary, and compiles the final executable to ./build/ironflow — plus the cloud binaries (ironflow-cloud, ironflow-cloud-recover, cloud-migrate-dek-keying).

Running the Dev Server

Build and start the server with SQLite (default):

Terminal window
make dev

This starts the server at http://localhost:9123. For active frontend/SDK development, you’ll typically use three terminals:

  1. Server: make dev — Core engine and API.
  2. Dashboard: cd apps/dashboard && pnpm dev — Vite dev server with HMR at :5173.
  3. SDK Watch: pnpm --filter "./sdk/js/*" dev — Rebuilds TypeScript packages on change.

Makefile Targets

TargetDescription
make allFull build: deps → embed → binary, plus the cloud binaries (ironflow-cloud, -recover, dek-keying)
make embed buildBuild a binary that can serve (dashboard embedded)
make buildGo binary only — don’t trust it to serve (see below)
make devBuild everything and start dev server
make protoGenerate Go/TS code from protobuf (requires Buf CLI)
make testRun all tests (Go, Go SDK, JS SDK)
make test-goRun Go tests (main module + Go SDK)
make test-jsRun JS SDK tests + the dashboard suite
make test-pgRun Go tests with PostgreSQL (requires Docker)
make lintRun golangci-lint on Go modules (main + SDK)
make cleanRemove all build artifacts and caches

make build bundles whatever dashboard assets are already sitting in internal/server/static/. That directory is gitignored, and make clean does not remove it. So a fresh clone gets no dashboard and serve refuses to start (embedded dashboard missing), while a tree you embedded weeks ago starts fine and silently serves the old dashboard. Run make embed build whenever the dashboard matters.


Docker Compose Stack

Instead of building from source, you can run the full Ironflow stack using Docker Compose. The repository’s docker-compose.single-node.yml uses profiles to compose exactly the services you need.

Quick Start (SQLite + Metrics)

Build and start everything in one command:

Terminal window
docker compose -f docker-compose.single-node.yml --profile monitoring up --build -d

This starts Ironflow (with SQLite) and Prometheus. Check the logs for your admin credentials:

Terminal window
docker compose -f docker-compose.single-node.yml logs ironflow

Available Profiles

ProfileServices AddedUse Case
(none)ironflow onlyMinimal — SQLite, no monitoring
postgresironflow + postgresProduction-like with PostgreSQL
monitoringironflow + prometheusMetrics and monitoring
BothAll three servicesFull stack

Profile Combinations

Terminal window
# Ironflow only (SQLite, no monitoring)
docker compose -f docker-compose.single-node.yml up --build -d
# Ironflow + PostgreSQL
docker compose -f docker-compose.single-node.yml --profile postgres up --build -d
# Ironflow + Prometheus
docker compose -f docker-compose.single-node.yml --profile monitoring up --build -d
# Full stack: PostgreSQL + Prometheus
docker compose -f docker-compose.single-node.yml --profile postgres --profile monitoring up --build -d

Enabling Observability

Prometheus metrics are enabled by default in Docker Compose (IRONFLOW_METRICS_ENABLED defaults to true in docker-compose.single-node.yml). When running outside Docker (e.g., make dev), metrics are off by default; set IRONFLOW_METRICS_ENABLED=true to enable. The /metrics endpoint is available when metrics are enabled, and Prometheus scrapes it automatically when the monitoring profile is active.

To also enable distributed tracing, set the OTel endpoint in a .env file:

Terminal window
# .env (optional, for distributed tracing)
IRONFLOW_OTEL_ENDPOINT=localhost:4317

Useful Commands

Terminal window
# View logs
docker compose -f docker-compose.single-node.yml logs -f ironflow
# Open Prometheus UI (when monitoring profile is active)
open http://localhost:9090
# Stop all services (data preserved)
docker compose -f docker-compose.single-node.yml --profile postgres --profile monitoring down
# Stop and delete all data (full reset)
docker compose -f docker-compose.single-node.yml --profile postgres --profile monitoring down -v
# Rebuild after code changes
docker compose -f docker-compose.single-node.yml --profile monitoring up --build -d

Service Ports

ServicePortURL
Ironflow9123http://localhost:9123
Ironflow Metrics9123http://localhost:9123/metrics
PostgreSQL5432127.0.0.1:5432 (localhost only)
Prometheus9090http://localhost:9090

When to use Docker vs make dev

Use make dev when you’re actively developing Ironflow itself (Go code, dashboard, SDKs) — it provides faster iteration with hot-reload. Use Docker Compose when you want to test the full containerized stack, verify Docker builds, or run with PostgreSQL and Prometheus without installing them locally.


SDK Development

Ironflow is a monorepo. Changes to the core protocol (api/proto) must be propagated to the SDKs.

Protocol Changes

If you modify a .proto file in api/proto/ironflow/v1/:

  1. Run make proto to regenerate the Go and TypeScript code.
  2. Check api/go/ and sdk/js/core/src/gen/ for the updated files.

JavaScript/TypeScript SDK (sdk/js/)

The JS SDK is a pnpm monorepo consisting of:

  • @ironflow/core: Generated types and shared logic.
  • @ironflow/node: Worker and server-side utilities.
  • @ironflow/browser: Browser-optimized client.
  • @ironflow/langgraph: LangGraph checkpoint saver for durable agent state.

Workflow:

Terminal window
# Setup
make sdk-js-install
# Build and Test
make sdk-js-build
make sdk-js-test
# Local iteration (watch mode)
pnpm --filter "./sdk/js/*" dev

Go SDK (sdk/go/ironflow/)

The Go SDK is a standard Go module.

Workflow:

Terminal window
# Run tests
cd sdk/go/ironflow
go test -v ./...

Testing SDKs in External Projects

To test your local changes in a real application without publishing to npm or GitHub:

JS SDK (using Tarballs)

  1. Pack the SDK:

    Terminal window
    make sdk-js-pack

    This creates .tgz files in /tmp/ironflow-packs/.

  2. Install in your app:

    Terminal window
    pnpm add file:/tmp/ironflow-packs/ironflow-node-<version>.tgz

Go SDK (using replace)

Add a replace directive to your application’s go.mod:

go.mod
module my-app
go 1.25
require github.com/sahina/ironflow-go/ironflow v0.0.0
replace github.com/sahina/ironflow-go/ironflow => ../path/to/ironflow/sdk/go/ironflow

Engine-internal vs public-mirror path

The LHS of both lines uses the public mirror path (github.com/sahina/ironflow-go/ironflow) — that is the path every other consumer of the SDK imports, and the path Go resolves against the module proxy. The RHS of replace points at the engine-internal path on disk (sdk/go/ironflow/), which has its own go.mod declaring module github.com/sahina/ironflow/sdk/go/ironflow for in-repo imports. Go’s replace directive substitutes the path → file mapping, so the two paths do not need to align. See ADR 0022 for the full convention.


Troubleshooting

“Bootstrap” Missing in Logs

The admin password and API key are only printed on the first run. If you missed them:

  1. Stop the server.
  2. ironflow serve --dev --reset (for SQLite — wipes local state and reboots fresh; or make clean-data) or make docker-reset-pg (for Postgres).
  3. Restart the server.

Protobuf Generation Failures

If make proto fails, verify your Buf installation:

Terminal window
buf --version
# Should support buf.yaml v2 format (buf >= 1.27)

Database Lock (SQLite)

If you see database is locked, another Ironflow process is likely running. Use lsof -i :9123 to find and kill it.


Next Steps