publish / unpublish
n8n-decanter publish [workflow…] # take the draft(s) live
n8n-decanter unpublish [workflow…] # return to draft-only
n8n 2.x splits each workflow into a draft and a published version. In the editor, Save updates the draft and Publish makes it live. Every decanter push updates the draft only — these verbs are the deliberate go-live half:
publishtakes the draft live — the code runs from now on. On a published workflow whose draft has diverged (pushes, or UI edits), it promotes the newer draft.unpublishreturns the workflow to draft-only.
From n8n 2.40 on, going live takes a moment. n8n marks the new version
as published at once, then activates it in the background. Until that is
done, the previous version keeps running. Measured on n8n 2.44.5 over 50
publishes, in regular and in queue mode: a webhook call made right after
publish returned ran the previous version every time. The new one answered
after about 0.4 s as a rule, and after 2.3 s at the slowest. decanter can’t
wait for it: n8n reports that status only to a signed-in editor session, not
over MCP or its public API. So if a script calls the webhook straight after
publish, give it a few seconds, or check the run’s version. Unpublishing
works the same way.
Both go over n8n’s MCP server. Without refs they act on the workflows listed
in decanter.config.json. push --publish combines a push with the publish
in one command.
The go-live gate
publish refuses a draft carrying a dangling $('…') reference — one that
names a node the workflow doesn’t have. That reference fails at run time, so
publishing it would put a known break into production.
The check runs against the draft on the instance, not your local folder.
That is deliberate: workflow.json is a snapshot, so grading it here would pass
a broken workflow whenever the local mirror is out of date, and block a
legitimate publish from a fresh clone. It costs nothing extra — publish
already reads the draft to decide what to do.
It is the same check test runs bare, and the message names
both halves and the order to repair them in. Running it in both places is not
redundant: the instance can change between the two, so only the check inside
publish is authoritative for that publish.
The usual cause is a rename — n8n’s renameNode MCP op rewrites the node name
and the connections only, and leaves every reference behind. See
pull.
Already in that state
Running publish when the live version already equals the draft (or
unpublish on an already-draft workflow) is a no-op with a note, not an
error — nothing changes and the command still exits 0.
The standard loop
n8n-decanter push wf # update the draft (live version untouched)
# …iterate, test, repeat…
n8n-decanter publish wf # ship it — or use push --publish for the last one
Because pushes never auto-publish, there is no need to unpublish first for
a staged rollout — the draft accumulates changes while the published version
keeps running.