DEV Community

Paul Crinigan
Paul Crinigan

Posted on

A Workflow Engine That Fits On Three Dollar Hosting

Most automation stories start with a platform and end with a bill. The version worth telling starts smaller. A form submission has to reach the CRM. An order needs a fulfillment call and a confirmation text. A daily report gets assembled by hand every morning because nobody ever wired it up. That glue work is the same in every business, and it does not need a cluster. It needs somewhere to live that you control.

Workflow Chain Engine is the open source engine I maintain for exactly that job. You draw a flow in the browser, it calls your APIs, branches on the answers, loops over lists, and records every run. It is one PHP application with a single SQLite file, MIT licensed, and it is at home on a three dollar shared host, a VPS, or a Docker container.

Why Self Hosted Automation Keeps Coming Back

Cost is the obvious reason, and it is not the interesting one. The interesting one is that automation touches your credentials. Every flow you build holds API keys for your CRM, your payment provider, your chat tool. When those keys live inside somebody else's platform, your blast radius is their incident report.

Running the engine yourself puts the workflows, the credentials and the run history in one folder you can back up by copying it. The editor library ships inside the project, so the whole tool works on your server with nothing loaded from anyone else's. There is no build step and no dependency install, which is why it fits on hosting you might otherwise be embarrassed to admit you use.

Integration works the way the web already works. Any service with an HTTP API is one node away: fill in the URL, the fields and the headers, and the flow talks to it.

The Six Nodes That Cover Most Real Work

There are six node types, and the restraint is the point. HTTP Request does GET, form POST or JSON POST to any URL, with per node headers for API keys and a capture feature that pulls values out of the response into variables. Write capture total={data.total} to walk an exact path, or status={status} to find the first matching field anywhere in the response.

If Condition branches on a variable with equals, greater, less, contains and length checks, and it understands numbers when both sides are numeric. Switch matches one variable against any number of cases, each with its own path plus a default, so an inbound order type fans out to the right handler. Set Variable assigns a value and resolves placeholders inside it, which makes it a string builder as well.

For Each Loop runs a chain of nodes once per item in a list, either a captured JSON array or comma separated text, with loopItem and loopIndex available inside the body. Success End and Fail End stop the run with a status and a message that resolves variables too, so the caller gets back "Processed Acme, total 42" instead of a bare acknowledgement.

Data moves through one flat pool. Each workflow declares its variables by name, the trigger fills them at the start, any node field can reference them, HTTP nodes capture responses back into them, and the run history shows their final values. One visible pool per run is what keeps a branching flow readable a month later.

Triggers And A Run History You Can Read

A flow can start four ways. Every workflow gets its own webhook URL secured by its own long random key, so a form, a store or a payment provider can post straight into it and get the run's real result back. Your own code can trigger a run with one authenticated POST, and a listing endpoint returns every workflow with its variables so other systems can discover them. Schedules handle the every X minutes case, through the Docker image's scheduler or a single crontab line on ordinary hosting. Run Now is a button in the admin with an input box per variable, which is how you test while building.

Then there is the part that decides whether you keep using a tool. Every run is recorded with its trigger, status, duration and step count, plus a step by step log. The HTTP node logs the URL, the response status and an excerpt of the body. The condition node logs the comparison it made and which way it went. The loop logs how many items it walked. When a flow misbehaves overnight, the run history tells you which step did what with which data, and the fix is usually obvious on one read.

Loops are safe by construction. Every run has a step budget, 500 node executions by default and adjustable, and a run that reaches it stops itself with a clear error naming the problem. That single rule means you can wire a condition back to an earlier node for repeat until behavior without worrying that you just built something that never ends.

Start With One Flow You Already Do By Hand

The best first workflow is boring and already exists as a habit. Pick the thing somebody on your team does every morning, the copy from one tab into another, and wire it: a webhook or a schedule at the front, one HTTP node, one condition, an end node with a message that says what happened. Watch it run, read the log, then add the second branch.

Requirements are PHP 8.1 or newer with pdo_sqlite and curl. Copy the sample config, set your API key and admin password, and either run PHP's built in server locally, docker compose up, or upload it and point a docroot at the public folder. The source is on GitHub under MIT, and the full documentation lives with the project.

Top comments (0)