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:
git clone https://github.com/sahina/ironflow.gitcd ironflowmake allmake 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):
make devThis starts the server at http://localhost:9123. For active frontend/SDK development, you’ll typically use three terminals:
- Server:
make dev— Core engine and API. - Dashboard:
cd apps/dashboard && pnpm dev— Vite dev server with HMR at:5173. - 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:
docker compose -f docker-compose.single-node.yml --profile monitoring up --build -dThis starts Ironflow (with SQLite) and Prometheus. Check the logs for your admin credentials:
docker compose -f docker-compose.single-node.yml logs ironflowAvailable 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
# Ironflow only (SQLite, no monitoring)docker compose -f docker-compose.single-node.yml up --build -d
# Ironflow + PostgreSQLdocker compose -f docker-compose.single-node.yml --profile postgres up --build -d
# Ironflow + Prometheusdocker compose -f docker-compose.single-node.yml --profile monitoring up --build -d
# Full stack: PostgreSQL + Prometheusdocker compose -f docker-compose.single-node.yml --profile postgres --profile monitoring up --build -dEnabling 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:
# .env (optional, for distributed tracing)IRONFLOW_OTEL_ENDPOINT=localhost:4317Useful Commands
# View logsdocker 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 changesdocker compose -f docker-compose.single-node.yml --profile monitoring up --build -dService 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/:
- Run
make prototo regenerate the Go and TypeScript code. - Check
api/go/andsdk/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:
# Setupmake sdk-js-install
# Build and Testmake sdk-js-buildmake sdk-js-test
# Local iteration (watch mode)pnpm --filter "./sdk/js/*" devGo SDK (sdk/go/ironflow/)
The Go SDK is a standard Go module.
Workflow:
# Run testscd sdk/go/ironflowgo 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)
-
Pack the SDK:
Terminal window make sdk-js-packThis creates
.tgzfiles in/tmp/ironflow-packs/. -
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:
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/ironflowEngine-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:
- Stop the server.
ironflow serve --dev --reset(for SQLite — wipes local state and reboots fresh; ormake clean-data) ormake docker-reset-pg(for Postgres).- Restart the server.
Protobuf Generation Failures
If make proto fails, verify your Buf installation:
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
- Architecture — Deep dive into the internal engine.
- API Reference — API protocol specifications.
- GitHub Issues — Pick up a “good first issue.”