Skip to main content
deploy is the command you run day to day: it compiles every bound component, uploads only the definitions whose document actually changed, and runs the platform’s own check_definition against each workflow definition it uploaded. Re-running it with nothing changed uploads nothing and says so. It is build plus push plus check, with one difference that matters at each step: it refreshes the import allowlist live, it skips definitions that would upload identically, and it checks after every upload has finished rather than between them.

Synopsis

What it does

  1. Resolves the blob and revision. This is a write: status ready, phase draft or managed.
  2. Refreshes the import allowlist live. Reading it needs an admin-scoped key. On success the cache under ~/.blobhub/cache/allowlist/ is rewritten, so a later build verifies against something current. On a 403 — which is what the read/write keys the platform recommends for automation get — it falls back to that cache, and with no cache either it raises ALLOWLIST_UNREADABLE and degrades exactly as build does.
  3. Lists the revision’s definitions in both categories and matches the manifest against them.
  4. For each entry: compiles every bound component into an in-memory copy of the document, applying the same remote-edit gate, --force and --strict-imports as build.
  5. Compares that document against the remote one. Equal means skipped — no upload, and the local file is not rewritten either.
  6. Otherwise writes the built document to source, creates the definition if its alias is absent, and uploads.
  7. Once every entry above is done, and not before, runs check_definition against each workflow-category definition it uploaded.
The unchanged line names a bare alias where every other line names category/alias; on a revision where one alias legitimately names both a workflow and a playground definition, read it together with the lines above it. Under --json the payload carries created, uploaded, unchanged, planned, skipped_check, checked, dry_run and drift, alongside the envelope’s schema_version. checked holds the checker’s own events per definition, not just a status.

Uploads and checks are two passes, on purpose

Every changed definition is uploaded before the first check runs. Compilation and upload do interleave — each definition is compiled and uploaded before the next one is read — but no check runs until the last upload has finished. The obvious alternative, checking each definition right after uploading it, is worse, and the reason is that deploy cannot roll back an upload. Stopping at the first failing check would leave one definition on its new code and its sibling still on the old one: a half-deployed revision. And it would leave that behind on top of an incomplete report, because the checks for everything after the failure never ran. Finishing every upload first means a failing check is always reported against a fully applied deploy. A CHECK_FAILED from deploy therefore says the upload happened and the result does not pass, never the upload was refused. The definition is on the revision. Fix it and deploy again. Within the check pass itself, deploy reports the first failure and stops. To see every failing definition at once, run blobhub workflow check, which collects them all.

Playgrounds are not checked

check_definition loads the workflow manifest unconditionally, so running it against a playground definition checks it against the wrong manifest and produces meaningless findings. deploy skips it and says so on its own output line rather than silently. A playground is still uploaded exactly like a workflow definition; only the check is skipped.

What counts as unchanged

The comparison is the full serialized document, local against remote — not a hash of the code, not a timestamp. A definition is skipped only when everything about it matches: components, connections, ports, the compiled content[], and the attributes the compiler stamps. Two consequences worth knowing:
  • An unchanged definition leaves its local file untouched. deploy writes source only for the definitions it uploads. In the ordinary case the file on disk already equals the built document, so there is nothing to write; if it does not, run build to bring the file itself up to date.
  • Someone else’s browser edit does not stop the upload. The remote-edit gate reads the code port in the local definition file, which is all build has to work with. A change made in the visual editor and never pulled is simply a document difference, so deploy uploads over it. On a revision other people edit in the browser, run diff first — it is the only command that reports the remote’s state.

--dry-run

Reports the intended calls without compiling, uploading, or writing anything — including the allowlist cache, which a dry run reads offline rather than refreshing:
The plan comes from presence alone. Nothing is compiled, so a dry run cannot tell you which definitions would turn out unchanged, and cannot surface a compile error. diff answers both of those; --dry-run answers which calls would be made.

Errors

IMPORT_UNAVAILABLE reads differently here than under build: deploy holds the live allowlist, so its message appends what that allowlist currently permits. DEFINITION_SIZE_NEAR_LIMIT fires at 8 MB — 80% of the platform’s 10 MB payload ceiling — so a definition that is growing tells you before an upload starts failing at the gateway. Every code above, with its remediation, is in Error codes.

See also