Skip to content

Comparison

Last verified: September 2026. Vendor facts decay — please file an issue if anything below is out of date.

Every comparison below answers the same question: where does the product start?

The starting point determines what’s native and what’s bolted on. Ironflow starts from the recorded fact — every event and every recorded workflow step is the same kind of thing in one continuous history. Competitors start from workflows, event streams, or function triggers. They can add the other capabilities, but the foundation determines which ones emerge naturally and which feel stapled on.


High-Level Comparison

FeatureIronflowTemporalInngestHatchetRestateKurrentKafka
Starting PointThe recorded factThe workflowThe function triggerThe durable taskThe state machineThe event streamThe append-only log
ArchitectureSingle Binary (Embedded NATS)Cluster (Server + DB + UI; ES/OpenSearch optional)Managed cloud, or self-hosted server + RedisServer + PostgreSQL (RabbitMQ optional)Single binary; HA cluster (GA)Server (clustering Enterprise-only from 26.2)Cluster (KRaft brokers, ZooKeeper removed in 4.0)
Unified HistoryNative — events and execution in one timelineNo — separate systemsNo — events retained per plan window, runs separateNo — execution event log onlyNo — retention-bounded journalPartial — events only, no executionNo — log only, assemble everything
Local DXZero-Configtemporal server start-dev (in-memory by default)npx inngest-cli dev (no Docker)Docker (Hatchet Lite) or embedded mode (Go stable; TS/Python beta)Single binary (brew/npm)Docker (deb/rpm on Linux; no macOS package)Tarball + JVM, single-node KRaft
ExecutionPush (HTTP) & Pull (HTTP polling)Pull (gRPC)Push (HTTP) & Connect (WebSocket workers)Workers (bidirectional gRPC stream)Push (HTTP/2, Lambda)N/A (no execution)N/A (no execution)
State StoreSQLite / PostgresMySQL / PG / CassandraSQLite / PG + Redis (self-host) or managedPostgreSQLEmbedded RocksDB + replicated logEvent StoreTopic partitions
Learning CurveLowHigh (Complex primitives)LowLowMediumMedium (ES concepts)High (Ops-heavy)

vs. Temporal

Temporal starts from the workflow. Ironflow starts from the recorded fact. Temporal can add event storage, but workflow steps and domain events will always be separate systems that happen to coexist — a bundle. In Ironflow, a workflow step completing IS a recorded fact, the same kind of thing as a domain event. That’s why you can query “show me everything that happened to order-123” and see both in one timeline. That capability emerges from the foundation — you can’t bolt it on.

Temporal is the gold standard for durable execution at enterprise scale. If you need millions of concurrent workflows across a distributed cluster, Temporal is battle-tested.

Where Ironflow differs: Temporal treats workflows and events as separate concerns. You can emit signals and queries, but the workflow history and your domain events live in different systems. In Ironflow, they’re the same history — which is why history navigation (time-travel debugging), history correction (hot patching), and unified entity timelines work out of the box.

IronflowTemporal
Setupironflow servetemporal server start-dev (in-memory; --db-filename for SQLite) or self-hosted cluster
Unified historyEvents + execution in one timelineWorkflow history only
DebuggingHistory navigation, correction, editingReplay-based, Web UI
Scale modelSingle node (SQLite) or multi-node cluster (Postgres + external NATS)Distributed cluster (millions)

Choose Temporal if you need massive distributed scale with proven enterprise support, or its Durable AI integrations (OpenAI Agents SDK, LangGraph, Pydantic AI). Choose Ironflow if you want events and recorded execution in one history and the tools to correct that history in production.


vs. Inngest

Inngest starts from the function trigger. Events kick off workflows and are retained for a plan-dependent window (hours to days) so you can inspect and replay them — but they are execution inputs, not a domain history. In Ironflow, events are permanent recorded facts. Workflow steps are permanent recorded facts. The trigger and the execution live in the same history. Inngest’s event store and run store are two systems sharing a product, not one unified history.

Inngest delivers excellent developer experience for serverless workflows. If you’re building on Vercel/Next.js and want managed infrastructure, Inngest is polished. Self-hosting is supported (SSPL with an Apache-2.0 future grant; SQLite or Postgres plus Redis), and the Connect mode adds persistent WebSocket workers alongside push.

Where Ironflow differs: Inngest treats events as triggers with a retention window — queryable via Insights, replayable in bulk, then gone. There are no entity streams, no projections to derive, no entity timeline to browse. Ironflow treats events as permanent facts that power projections, entity streams, and time-travel.

IronflowInngest
EventsPermanent recorded factsTriggers retained for a plan window (1h–3d lookback)
Event sourcingNative (entity streams, projections)Not available
HostingSelf-hosted (single binary)Managed cloud or self-hosted (SSPL)
Execution modesPush + PullPush + Connect (WebSocket workers)

Choose Inngest if you want a managed cloud service with zero ops for serverless functions. Choose Ironflow if you want your events to be permanent history, not disposable triggers.


vs. Hatchet

Hatchet starts from the durable task. Workers hold a gRPC stream to the engine, PostgreSQL is the source of truth, every checkpoint persists, and the dashboard replays the execution log. It’s a sharper Temporal: same shape, simpler ops, MIT-only. But the durability is execution-shaped, not domain-shaped — if you want your domain events and your workflow steps in the same history, Hatchet keeps them in different stores.

Hatchet is the cleanest “Temporal but Postgres-only” pitch in the market. If your team already runs Postgres, doesn’t need a separate broker, and wants a familiar workflow-engine model, Hatchet is sharp. Its new embedded mode bundles the engine and Postgres in-process for local dev (stable in Go, early beta in TypeScript and Python).

Where Ironflow differs: Hatchet’s “durable” means the execution event log — task started, task completed, retry attempted, plus durable event waits scoped to a run. Ironflow’s “durable” means the recorded fact — your domain events and your workflow steps in one continuous history. That’s why entity timelines, projections, and time-travel across workflows + events all work in Ironflow and don’t exist in Hatchet.

IronflowHatchet
StorageSQLite (dev) / Postgres (prod) + embedded NATSPostgreSQL (source of truth and queue; RabbitMQ optional)
Durability scopeDomain events + execution steps in one historyExecution event log only
Execution modesPush + PullWorkers over bidirectional gRPC only
Agent surfaceagent() handler with ctx-injected tool / llm / approve / memory / spawn + MCP server (ironflow mcp)Generic tasks; child tasks as tools, compatible with Claude / OpenAI agent SDKs (no agent API)
History toolsTime-travel, hot patching, scoped injection, TUI/DAPDashboard replay

Choose Hatchet if you want a sharper Temporal with Postgres-only operational simplicity for plain task workloads. Choose Ironflow if you want events and execution in one history, agent-native primitives, and history navigation/correction built in.


vs. Kurrent (EventStoreDB)

Kurrent starts from the event stream. Ironflow starts from the recorded fact. Kurrent records your data changes — and now offers SQL over them (Queries UI, Flight SQL) and atomic multi-stream appends. But your workflow execution, your authorization decisions, your debugging sessions will always live somewhere else. In Ironflow, those are all recorded facts in the same history. Cross-concern time-travel and an auditable history emerge from that unification.

Kurrent is the pioneer of event sourcing databases. If you need a dedicated, high-performance event store with mature subscription APIs, KurrentDB is the original. Note the license shift: it is source-available (Kurrent License v1), and from 26.2 multi-node clustering, read-only replicas, archiving and encryption-at-rest are Enterprise-only, while single-node production stays free.

Where Ironflow differs: Kurrent stores your domain events but doesn’t execute workflows. Its answer to sagas is multi-stream atomic append; for durable execution you need a separate orchestrator (Temporal, MassTransit, etc.). In Ironflow, workflow steps and domain events are both recorded facts in the same history — so you can see everything that happened to an entity in one view.

IronflowKurrent
Event storageBuilt-in (entity streams)Dedicated event store
Workflow executionBuilt-in (durable, memoized)Not available (need separate tool)
ProjectionsBuilt-in (managed + external)JS projections (V1 maintenance, V2 experimental); SQL is query-only and license-gated
Unified historyEvents + execution togetherEvents only

Choose Kurrent if you need a dedicated event store with mature subscription APIs and are fine with clustering behind an Enterprise license. Choose Ironflow if you want event sourcing and workflow execution unified in one history.


vs. Kafka

Kafka gives you the philosophy (append-only log) without the platform. You get the foundation but you assemble everything yourself — consumers, projections, workflow orchestration, monitoring. Ironflow gives you the same philosophy as a complete platform. Same starting point, none of the assembly.

Kafka is the industry standard for high-throughput event streaming. If you need to process millions of events per second across a distributed cluster, Kafka is proven.

Where Ironflow differs: Kafka gives you the log and leaves you to build everything on top — consumers, state management, workflow orchestration, projections, monitoring. Ironflow gives you the same append-only philosophy as a complete platform with workflows, projections, time-travel, and a dashboard.

IronflowKafka
SetupSingle binary, <500ms bootJVM + KRaft (single node for dev, multi-broker cluster for prod)
WorkflowsBuilt-in durable executionNot available (need Flink, Temporal, etc.; share-group queues since 4.2 are delivery, not orchestration)
ProjectionsBuilt-inNot available (Kafka Streams is a client library you deploy)
DashboardBuilt-inNot included (need Confluent, AKHQ, etc.)

Choose Kafka if you need massive throughput event streaming for data pipelines. Choose Ironflow if you want the append-only philosophy as a complete platform.


vs. Restate

Restate starts from the distributed state machine. Ironflow starts from the recorded fact. Restate provides durable execution with an embedded state store and a SQL-queryable journal, but that journal is retention-bounded (24h by default) and events and execution remain separate concerns. In Ironflow, they’re the same history.

Restate offers durable execution with an elegant virtual object model, shipped as a single binary (BSL 1.1) with GA multi-node clusters, Restate Cloud, and Vercel AI SDK / OpenAI / LangChain agent integrations. If you’re building distributed state machines with strong consistency, Restate is innovative.

Where Ironflow differs: Restate focuses on durable execution and state management but doesn’t provide event sourcing, projections, or unified entity timelines. Ironflow’s recorded-fact foundation means all of these emerge naturally.

IronflowRestate
Event sourcingBuilt-inNot available
ProjectionsBuilt-inNot available
State modelEvent-sourced (derived from history)Virtual objects (mutable state)
Unified historyEvents + execution in one timelineExecution journal only (24h default retention)

Choose Restate if you want distributed virtual objects with strong consistency guarantees. Choose Ironflow if you want execution and events in one continuous history.


Key Differentiators

1. One History

Every competitor keeps two records: the workflow engine’s execution log and, somewhere else, your domain events. Restate’s journal expires after 24 hours by default. Inngest retains events for a plan window. Hatchet logs execution only. Kurrent keeps events and has no execution. Ironflow keeps one record: a domain event and a completed step are the same kind of fact in the same timeline.

  • Ask “what happened to order-123” and get events, steps, and projections in one answer
  • Projections and entity streams derive from the same history that workflows write to
  • Nothing to join, sync, or reconcile across an event store and an orchestrator

2. History You Can Edit (The “Workflow DVR”)

Competitors added replay and introspection this year. None added correction. Because every step is a recorded fact, Ironflow can change the record and continue from it:

  • History Correction (hot patching): Edit a failed step’s output in production and resume execution.
  • History Navigation (time-travel debugging): Scrub through any execution frame-by-frame.
  • History Editing (scoped injection): Pause a running workflow, modify step data, resume.
  • TUI Debugger: Step through production runs in your terminal.
  • DAP Support: Attach VS Code to a production run ID.

3. Push + Pull From One History

Restate is push-only; Temporal and Hatchet are worker-only; Inngest added Connect for persistent workers next to push. Ironflow runs both modes against the same history, so a serverless push function and a long-running pull worker write to the same entity timeline.

  • Push Mode: Best for Next.js, Lambda, and serverless. Ironflow calls you.
  • Pull Mode: Best for AI/ML, video processing, and long-running tasks. Your worker polls Ironflow over HTTP.

Single-binary local dev (embedded NATS JetStream + SQLite, cold boot to /health under 500ms in the TestBootTime bench — see Benchmarks) is still there. It is no longer the differentiator: Restate ships a single binary too, and Hatchet, Inngest and Kafka all run Docker-free locally now.


Code Comparison

Ironflow (TypeScript)

import { createFunction } from "@ironflow/node";
const processOrder = createFunction(
{
id: "process-order",
triggers: [{ event: "order.placed" }],
recording: true, // Every step becomes a recorded fact
},
async ({ event, step }) => {
const payment = await step.run("charge", () => stripe.charge(event.data.total));
await step.sleep("wait-for-inventory", "5m");
return { success: true };
}
);

Temporal (Go)

func OrderWorkflow(ctx workflow.Context, order Order) (OrderResult, error) {
options := workflow.ActivityOptions{ StartToCloseTimeout: time.Minute }
ctx = workflow.WithActivityOptions(ctx, options)
var result ChargeResult
err := workflow.ExecuteActivity(ctx, ChargeActivity, order).Get(ctx, &result)
if err != nil { return nil, err }
workflow.Sleep(ctx, 5*time.Minute)
return OrderResult{Success: true}, nil
}

When to Choose Ironflow

  • You want one history, not many: Events, workflow steps, and projections in one unified timeline per entity.
  • You need to fix a production run, not just replay it: Hot patching, scoped injection, and time-travel are correction tools, not viewers.
  • You need an auditable history: With recording enabled, the audit trail is derived from the same history, not a separate layer to build.
  • You are event-sourcing already: Entity streams, projections, and upcasters are native, and the workflow that reacts to an event lands in the same stream.
  • You are building an AI agent: agent() handlers with approve / memory / spawn write to the same history as everything else, so an agent run is debuggable like any other run.
  • You are on the edge: Single Go binary for limited-resource environments.

Performance & Scale

Published numbers come from the in-tree bench suite (make bench + k6 load tests). See Benchmarks for thresholds, methodology, and how to reproduce on your hardware.

MetricIronflowTemporalInngestHatchetRestate
Setup Time<1 minute (single binary)Minutes (start-dev); hours for a self-hosted clusterMinutes (dev server)Minutes (embedded mode or Docker)Minutes (single binary)
Boot Time<500ms (TestBootTime warn threshold)Not publishedN/A~25ms p95 dispatch (server boot not published)Not published
Load-test p95event-emission <500ms, mixed-workload <1s, function-invoke <10sNot directly comparableCloud-managedNot publishedNot published
Throughput (vendor-published)Not yet published — depends on hardware + storage backend450k actions/s (Cloud)Not published10k tasks/s load test; ~25ms p95 dispatch84k actions/s, 3-node bench (v1.2)
Memory FootprintNot yet publishedNot publishedN/A (Cloud)Not published~1.5 GiB minimal, ~4.75 GiB default (documented)

Summary

Ironflow is the first Continuous History platform — events and execution unified in one recorded history, with the tools to navigate and correct it.

Other platforms start from workflows (Temporal), function triggers (Inngest), event streams (Kurrent), or append-only logs (Kafka) and can add the missing pieces. Since April they have: single binaries, Docker-free dev servers, retained events, SQL over journals, agent SDKs. But the result is still a bundle — separate systems coexisting in one product. The emergent capabilities (unified entity timelines, cross-concern time-travel, history correction) don’t appear because the foundation isn’t unified. Ironflow’s foundation is.