Skip to content
Fluxify

architecture

Compile the graph once. Never walk it again.

Your flow is a directed acyclic graph of blocks. Fluxify turns it into JavaScript when you save, so the work done per request is the work your blocks actually do — not the bookkeeping of interpreting them.

From save to live

You hit Save editor PostgreSQL blocks + edges Compiler graph → JS NATS KV compiled routes Worker swapped in place Worker swapped in place Worker swapped in place blocks, edges and route settings saved the source of truth; only admin connects walks from Entrypoint, emits one JS module stores the latest build and notifies workers no restart; in-flight requests finish on old code
Steps after Save happen once, automatically, usually in well under a second. Requests never touch the left half of this picture.

why it's fast

An interpreter pays a toll at every block.

Walking a graph at runtime means, for every block of every request: find what comes next, look up how that block type behaves, run it, wrap its output for the next one. Compiling removes the loop — a wire becomes a direct function call.

interpreted · the old engine · per request, per block request find next block look up its type run it wrap the output response ↻ 1.51 ms CPU / req compiled · the current engine · per request request $block_0 $block_1 $block_2 $block_3 response 0.86 ms CPU / req
Same route, same machine: CPU time per request fell from 1.51 ms to 0.86 ms once the loop disappeared.

a request on a worker

Four steps, two early exits.

Matching a path is a lookup, so adding routes doesn't slow the ones you have. Bad input is rejected before a single block runs.

no match schema fails your blocks request GET /users/42 Match route table lookup Validate body · query · params Run compiled module $run(ctx, input) 200 OK your Response block 404 Route not found 400 validation failed DB · KV · HTTP · queues through integrations
Rejections happen before any block runs. Everything after the match is your route's own compiled code.

topology

Two halves, deliberately unequal.

The control plane is where you build — run one. Workers are where your API runs — run many. Only the control plane can reach Fluxify's database.

Control plane fluxify-admin ×1 Request workers fluxify-worker ×N store publish cache ✕ no credentials starts & replaces workers Portal visual editor Admin API routes, blocks, settings Compiler graph → JS module AI gateway agent harness · alpha Orchestrator reconciles worker count every 5s PostgreSQL flows, users, settings NATS JetStream compiled routes (KV) Redis sessions, settings cache Worker compiled routes in memory Worker compiled routes in memory Worker compiled routes in memory Proxy Traefik Users Your databases & queues Postgres · Mongo · Redis · Kafka
Lime: compiled routes flowing to workers. Green: your users' requests. Red dashed: a connection that deliberately does not exist.
Control planeRequest workers
DoesEditor, admin API, compiler, AI gatewayServes your routes and runs workflows
Fluxify's PostgreSQLReads and writes itNever — no credentials are given
ScaleOne is plentyAdd more as traffic grows (Community: 1, Enterprise: no cap)
If it goes downYou can't edit; your API keeps servingThat worker stops answering; others carry on

deploys

Saving is deploying — without the downtime.

Workers watch for new builds and swap them into the route table in place. Requests already running finish on the version they started with.

time → v2 published you hit Save finishes on v1 finishes on v1 finishes on v1 runs v1 runs v2
A save swaps the route table in place. Nothing restarts, nothing is dropped, and a broken save never replaces the version that's serving.

state

Three stores, three jobs.

It's easy to assume the graph is cached somewhere and re-read on every request. It isn't: workers hold compiled code in memory.

PostgreSQL

source of truth · control plane only

Projects, users and roles, routes and workflows, every block and edge, triggers, test suites, orchestration state and the license. Read by the compiler at save time, never by a worker.

NATS JetStream

compiled routes · change events · required

Compiled routes live in a KV bucket, so a worker never needs a Postgres connection. The same bus carries hot-reload events for routes, settings, integrations and custom blocks. If NATS is down, Fluxify fails loudly instead of limping.

Redis

control-plane cache · and your KV store

Admin caches sessions, project settings and generated OpenAPI docs in Redis. Separately, Redis (or Memcached, Valkey, DragonflyDB) can be an integration your own flows use — like the cache-aside route on the home page.

database schema

A canvas is two tables.

What you draw is stored as plain rows — easy to back up, diff and migrate.

routes id varchar method varchar path text body_schema jsonb params_schema jsonb timeout_seconds int blocks id varchar type varchar data jsonb position jsonb route_id → routes edges id varchar from → blocks to → blocks from_handle b3-success to_handle b3-success route_id → routes on the canvas If Condition Response 200 1 edge row 2 block rows
A canvas is two tables. A block is a row with its config as JSON; a wire is a row naming two blocks and a socket. Position is layout only — the edges are the program.

benchmarks

What compiling is worth.

Same route, same data, same traffic — the old interpreting engine against the compiled one. Throughput and latency improved together, which only happens when each request genuinely got cheaper.

Interpreted vs compiled engine interpreted (graph walked per request) compiled (current engine)
Requests / second higher is better · +63%
860.7
1,403.2
Median latency lower is better · -43%
91 ms
51.5 ms
p95 latency lower is better · -25%
134.8 ms
101.1 ms
Fastest request lower is better · -87%
4.09 ms
0.53 ms
CPU time / request lower is better · -43%
1.51 ms
0.86 ms

One benchmark, one developer machine: GET /users?id=… ramped to 100 concurrent users for 60s, same route and data on both engines. Read the ratios, not the absolute numbers. The slowest single request was worse on the compiled engine (258 ms vs 215 ms) — likely GC or machine noise. Source: docs/architecture/performance.md.

MetricInterpretedCompiled
Requests / s860.71403.2
Requests in 60s51,65084,198
Average87.1 ms53.3 ms
Median91 ms51.5 ms
p90124.8 ms88.4 ms
p95134.8 ms101.1 ms
Slowest215 ms258 ms
Memory256 MB210 MB
CPU time / request1.51 ms0.86 ms

Where Fluxify isn't the bottleneck: a route waiting 200 ms on a slow upstream is dominated by that wait. This measures the engine's own overhead. Reproduce it with testing/load-testing.

Want the internals? Read the compiler or the architecture docs.