Skip to content

Local Development

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

Prerequisites

  • Go 1.25+ (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.

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

Target Description
make all Full build: deps → embed → binary
make build Build the Go binary only
make dev Build everything and start dev server
make proto Generate Go/TS code from protobuf (requires Buf CLI)
make test Run all tests (Go, Go SDK, JS SDK, cloud-workflows)
make test-go Run Go tests (main module + Go SDK)
make test-js Run JS SDK tests only
make test-pg Run Go tests with PostgreSQL (requires Docker)
make lint Run golangci-lint on Go modules (main + SDK)
make clean Remove all build artifacts and caches

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

Profile Services Added Use Case
(none) ironflow only Minimal — SQLite, no monitoring
postgres ironflow + postgres Production-like with PostgreSQL
monitoring ironflow + prometheus Metrics and monitoring
Both All three services Full 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

Service Port URL
Ironflow 9123 http://localhost:9123
Ironflow Metrics 9123 http://localhost:9123/metrics
PostgreSQL 5432 127.0.0.1:5432 (localhost only)
Prometheus 9090 http://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