Stand up your first instance
In this tutorial we bring the whole Meridian stack up on one machine with Docker Compose, open the config-plane in a browser, emit a clinical event, and watch a workflow run to completion. By the end we will have a working instance and will have seen a durable run go from event to finished — including one human validation.
We use the bundled development instance (instance.dev.yaml), which serves an
in-memory patient record. Nothing external is required: no FHIR warehouse, no
LLM key, no cloud account.
Before we start
We need:
- Docker with the Compose plugin (
docker compose versionshould print a version). - Node.js and pnpm (
pnpm --versionshould work) — used once to build the plugin bundles. - The repository cloned locally. Run every command from the repository root.
That is all. The stack we launch is four Meridian processes plus a FHIR warehouse container; the full picture lives in Topology.
Step 1 — Build the plugin bundles
The container image ships no external plugins: the local stack mounts them
from the host, so we build them first. This command bundles each external plugin
with meridian-plugin build (an esbuild bundling step — there is no
build-manifest to maintain):
pnpm run build:plugins
We should see one build line per plugin (demo, geriatrie, posos,
demo-softway) finish without error. Each now has a dist/ folder under
external-plugins/<name>/ containing compiled JS, its plugin.yaml, and its
i18n/ bundles.
Why bundle at all, and what ends up in
dist/? See Build and bundle.
Step 2 — Bring the stack up
Now we start every service with the stack profile and let Compose build the
images:
docker compose --profile stack up -d --build
The first build takes a few minutes. When it returns, Compose has started five containers:
- restate — the durable control plane (the run journal and recovery engine).
- endpoint — the workflow engine, which loads our plugins and the instance.
- proxy — the REST API on port
4000. - ui — the config-plane console on port
3000. - blaze — a FHIR warehouse used by the bundled EHR lab (not needed for this tutorial, but part of the profile).
The endpoint and proxy read the instance.dev.yaml manifest by default and load
the plugins we just built from the mounted external-plugins/ folder. To point
at a different manifest or change any of these settings, see
Environment variables and
The instance manifest.
Step 3 — Wait until the stack is healthy
The proxy container has a health check and the ui waits for it, so a healthy
proxy means the whole chain is ready. Let's watch the container states settle:
docker compose --profile stack ps
We wait until proxy shows (healthy). We can confirm readiness directly — the
proxy's readiness probe returns 200 only once both Restate and the run index
answer:
curl -i http://localhost:4000/readyz
A HTTP/1.1 200 OK response means we are ready to open the console.
Step 4 — Open the config-plane
Open http://localhost:3000 in a browser. We land on the Workflows view, which lists the workflows the engine loaded — among them Réception résultat biologie, the one we are about to run. Selecting it renders its graph: the event trigger on the left flowing through the clinical computation, a human validation, and the outbound alert.
Seeing the workflow here is our confirmation that the engine started, parsed the instance, and loaded the plugins.
Step 5 — Emit an event
We trigger a run by emitting the event the workflow listens for.
- In the top navigation, click Executions. The view is empty for now — "No event received."
- Click + Emit an event. A composer opens.
- Under Target workflow, choose Réception résultat biologie. The Event
payload (JSON) box fills in with an example payload for this trigger,
including a
patientIdthat exists in the in-memory record. - Leave the payload as-is and click ▶ Send the event.
The composer closes and a new run appears at the top of the Runs list.
Step 6 — Watch the run and clear the validation
The Executions view refreshes live (every couple of seconds). We watch the selected run's timeline fill in node by node: it loads the patient, computes the eGFR from the creatinine result, and detects a candidate condition.
The run then pauses at a human validation — its status turns to suspended
and a panel appears: "Human validation required." This pause is durable: the
run is journaled and waiting, not spinning. (Why the engine can suspend
indefinitely and resume exactly where it left off is covered in
Why durable execution.)
Review the proposed condition in the panel and click ✓ Accept.
Step 7 — See the run complete
Once we accept, the run resumes from the journaled point: it records the
condition, runs the renal drug-safety check, and — if it finds an issue — emits
the notification (in this dev instance the notification port is the console
adapter, so the alert is logged, not sent anywhere). The run's status badge
turns to completed and the timeline shows every executed node.
We have just stood up a Meridian instance and driven a clinical event all the way through a durable workflow, human validation included.
Where to go next
- Author your own workflow — Your first workflow.
- Read runs and validations in depth — Monitor executions.
- Point the instance at your own ports and adapters — Configure ports and adapters.
- Add plugins from a registry — Declare and install plugins.
- Move the run index to Postgres for a multi-replica proxy — Use a Postgres run index.
- Turn on traces, metrics, and logs — Enable observability.
Unfamiliar terms are defined in the Glossary.