Workflow Versioning
Workflows in Nembl are versioned with an immutable-snapshot model: each Publish snapshots a new version, you can have many published versions side-by-side, and consumers (service offerings, in-flight requests) bind to a specific version. This lets you iterate continuously without breaking what's already running.
Version States
Every version exists in one of three states. The state is computed from two timestamps on the version row (publishedAt, retiredAt):
| State | When | What happens |
|---|---|---|
| DRAFT | Created when you start editing a workflow that has no open draft. There can be at most one DRAFT per workflow at a time. | Editable. Not selectable by service offerings. Cannot accept production requests. |
| PUBLISHED | Created when you click Publish on a draft. Immutable from this point. | Selectable by service offerings; accepts production requests. |
| RETIRED | A PUBLISHED version that you've marked retired. | Hidden from the version picker on offerings. In-flight instances continue to run. New requests cannot pin to it via LATEST. |
A draft never becomes retired — only published versions can be retired. Discarding a draft just deletes it.
The LATEST Resolver
Service offerings can pin to a specific version (e.g. v3) or to the special token LATEST.
v3— every new request uses version 3 specifically, even after newer versions are published.LATEST— every new request resolves to the highest-numbered, non-retired, published version at request time.
Use LATEST for offerings where you want every improvement to take effect immediately. Use a pinned version when you've certified a specific version (compliance, change control) and want to require an explicit re-pinning to roll forward.
LATEST resolves at request time. Nembl computes the latest version dynamically — the highest-numbered, non-retired, published version — every time a new request resolves. There is no persisted "is latest" flag, so a newly-published version takes effect for new requests immediately.
Test vs Production Instances
Every workflow instance carries a kind — PRODUCTION (the default) or TEST.
| Kind | Created by | Counts toward billing | Visible in |
|---|---|---|---|
| PRODUCTION | Real request submissions, the manual Run Workflow button on a published version | Yes | All views (workers, admins) |
| TEST | The "Run Workflow" button on a DRAFT, API-driven smoke tests | No | Admin views only |
Test instances let you exercise a workflow end-to-end without polluting production reports. A TEST instance behaves identically to a PRODUCTION instance at runtime, but its outputs are tagged so analytics and billing roll-ups exclude them.
Draft Lifecycle
┌────────────┐ Edit a published version
│ (no open │ ──▶ creates open DRAFT
│ draft) │
└─────┬──────┘
│
│ Publish
▼
┌────────────┐
│ PUBLISHED │ ◀──┐
│ v(N) │ │ Edit again
└─────┬──────┘ │ → new DRAFT
│ │
│ Retire │
▼ │
┌────────────┐ │
│ RETIRED │ │ Restore
│ v(N) │ │
└─────┬──────┘ │
│ │
│ Restore │
├───────────┘
│
│ Delete (only if no instances)
▼
(gone)- One open draft per workflow. Publishing closes the draft and starts a new published version. Re-editing a published version opens a fresh draft.
- Restore returns RETIRED → PUBLISHED so you can roll back a retirement if you change your mind.
- Delete is only allowed for RETIRED versions with zero instances — production or test. Cascade is then total: phases, transitions, history all go.
- All-retired edge case. If every published version is retired, you can't open a new draft until you un-retire one (the editor needs a published baseline to fork from).
Working with Versions in the UI
Workflow detail page (Admin → Workflows → <workflow>):
- Versions card lists every version with state badge, version number, published / retired timestamps, and instance count
- Actions per version: View, Retire, Restore (if retired), Delete (if retired + empty)
- Editor entry opens the open DRAFT, or creates a fresh DRAFT from LATEST if none is open
Service offering picks the bound version:
- LATEST (default) — auto-rolls forward
- Specific version — explicit pin
When the bound version is retired, the offering's bind is not automatically updated. You'll see a warning on the offering, and new requests fail until you re-pin.
Best Practices
- Default offerings to LATEST. Reach for a pinned version only when you have a real change-control reason.
- Retire aggressively. Old versions clutter the picker and confuse operators. Retired versions are still safe — in-flight work keeps running on them.
- Don't delete unless you mean it. Deletion cascades to all instance history for that version. If you're not sure, retire instead.
- Use TEST runs from drafts to validate behavior end-to-end before promoting a draft to PUBLISHED. Run-Workflow-as-TEST from the editor is coming soon; in the meantime, use the API to start a test instance.
- Versions are per-workflow, not global. Workflow A's v3 is unrelated to Workflow B's v3. The version number is just a counter inside the workflow.
Related
- Builder Overview — drafting, saving, publishing
- Workflow Execution — what happens when an instance runs
- Service Offerings — picking which version an offering binds to