Flitzdocs
CLI

flitz publish

Build a bundle from your project against the pinned SDK and publish it; flags, output streams, --json, and the on-demand SDK download.

publish is the build-and-ship command. With a pinned SDK, the whole happy path is:

cd /path/to/your/flutter/app
flitz publish
✓ Compiling    12.3s
✓ Packaging     1.1s
✓ Uploading     3.8s  4.2 MB

Published acme_app in 17.2s

  Landing page  https://…
  Deeplink      flitz://download?url=…
  Bundle        https://…

followed by a QR code of the deeplink. Scan it with a host that has the Flitz loader embedded and the bundle downloads and runs. Share the landing-page link with a teammate and their browser shows the same QR plus an "open" button.

A bundle is a complete build of your app's Dart code — never a patch — and it runs only inside a host built against the same SDK tag. See How it works for the host/bundle split.

What happens

publish runs entirely in-process; there is no separate builder binary to fetch. It:

  1. Reads the pin from flitz.yaml in the current directory and resolves the cached SDK for that tag — fetching it first if you allow (below).
  2. Asks the Flitz service for upload and download links. This is the licensed call, so an unauthenticated or unlicensed publish fails here, with exit 3, before any compilation.
  3. Compilingflutter build bundle compiles the app to kernel, then dart2bytecode compiles the kernel to bytecode, validated against the dynamic interface that ships inside the pinned SDK. The interface always matches the SDK; there is no override flag.
  4. Packaging — writes manifest.json and packs it with the bytecode and flutter_assets/ into a ZIP that is encoded incrementally.
  5. Uploading — streams the archive straight into the upload as it is encoded, then uploads a single-file HTML landing page. The .flitz is never written to disk and never held whole in memory.

The published bundle lives in private storage. Possession of the unguessable link is what authorizes a download; there is no anonymous listing. The link stays valid for as long as the object exists — there is no expiry to re-publish around.

Share within your team

Anyone who holds the link can download the bundle, and a bundle runs with the full privileges of the host. Flitz is for your own team's work-in-progress builds, reviewed by collaborators during development; it is not a channel for delivering finished apps to outside users.

Flags

publish accepts the global options--json, --yes, -v, --no-color — plus these:

FlagDefaultPurpose
--app <dir>.The Flutter app directory; must contain pubspec.yaml. The SDK pin is still read from the current directory, not from --app.
--target <file>lib/main.dartDart entry point, relative to the app. Recorded in the bundle manifest as the entry library.
--target-platform <id>android-arm64 on Linux, ios on macOSForwarded to flutter build bundle. Drives which target's hook/build.dart runs when enumerating native assets. Values: android-arm, android-arm64, android-x64, ios, linux-x64, macos-arm64.
--dart-define <KEY=VALUE>, -DA compile-time constant, readable via String.fromEnvironment and friends. Repeatable; commas inside a value are not split. Values are redacted in every diagnostic, because defines routinely carry API keys.
--dart-define-from-file <path>A .json or .env file of compile-time constants. Repeatable. Resolved relative to the directory you ran flitz from.
--schema <scheme>flitzThe URL scheme of the emitted deeplink and QR. Must match the scheme your host registers; see URL scheme → Custom schemes. Affects only the deeplink, never the bundle.
--qr-output <path>Also write the deeplink QR as a standalone PNG. The parent directory must exist; an existing file is overwritten.
--no-qrSuppress the inline terminal QR. The result block is still printed.

There is no --output flag: publish never writes a .flitz to disk.

--dart-define values become constants in the compiled bytecode; they do not change the manifest, the deeplink, or the landing page. Reserved framework-managed defines cannot be set this way.

Output and --json

Progress and result use different streams. The three timed phases and the Published … in … line go to stderr; the labelled result block and the QR go to stdout. So

flitz publish > urls.txt

captures the three result lines and nothing else, while the terminal still shows the animated progress. The QR is drawn only when stdout is a terminal in rich mode; in plain output (CI, --no-color) the phases appear as timestamped lines and there is no QR.

The labelled block carries no line-format promise. Scripts read the result with --json, which replaces the block with one document on stdout and suppresses the QR:

flitz publish --json > result.json
{ "page_url": "https://…", "deeplink": "flitz://download?url=…", "bundle_url": "https://…" }
page=$(jq -r .page_url result.json)
deeplink=$(jq -r .deeplink result.json)
bundle=$(jq -r .bundle_url result.json)

On failure publish --json emits no JSON. Check the exit status first and parse stdout only on 0 — see Exit codes.

On-demand SDK download and --yes

publish works on a fresh checkout that contains only flitz.yaml. When the pinned SDK is not in the cache, it offers to fetch it:

The pinned SDK <tag> is not installed. Download it now (about 570 MB)? [Y/n]

Accepting runs the download in the same invocation — without re-pinning — and then continues the build. Declining aborts with the pinned SDK <tag> is not installed and the flitz sdk use <tag> hint (exit 1).

Non-interactively — a CI job, a redirected terminal — publish does not start a large unattended download. It fails immediately with that same error unless you pass --yes:

flitz publish --yes        # fresh checkout, no prompt, one command

--yes answers every prompt affirmatively; assume_yes: true in config.yaml does the same permanently. This offer exists only in publish. No other command downloads an SDK implicitly.

A one-command CI job, on a checkout that carries only flitz.yaml:

export FLITZ_APIKEY="$FLITZ_APIKEY_SECRET"   # from your CI secret store
flitz publish --yes --json

See flitz apikey → Using FLITZ_APIKEY in CI.

When it fails

Every failure follows the message convention: one sentence, then the next command. The exit code says which class of thing went wrong.

You seeCodeMeaning
no SDK is pinned for this project1No flitz.yaml with an sdk: key in the current directory. Run flitz sdk use latest here — the pin is not read from --app.
the pinned SDK <tag> is not installed1Non-interactive without --yes, or you declined the download.
pubspec.yaml not found at …1--app does not point at a Flutter app.
you are not logged in to Flitz / your Flitz session has ended / your organization's Flitz license is not active3Credential or license. Nothing was compiled.
kernel compilation failed (exit N)5flutter build bundle rejected the app; its diagnostics are printed verbatim above.
bytecode compilation failed (exit N)5dart2bytecode rejected the kernel. See Troubleshooting → Build failures.
the bundle destination is already occupied4A previous, interrupted publish reserved that object. Re-run; a fresh one is allocated.
the bundle upload failed: …4Re-run flitz publish.

Two partial-success cases are worth knowing. If the bundle upload succeeded but the landing-page upload did not, the failure message includes the bundle URL and the command exits 4 without a deeplink or page URL. If everything uploaded and the URLs were printed, a later local failure — a --qr-output PNG that could not be written — exits 2 without retracting the printed result.

Ctrl-C during a publish stops the build tool it started, deletes its scratch directory, and exits 2. If the interrupt landed during an upload, the notice adds that a partial object may remain at the destination and that re-running publish allocates a fresh one — which is why the "already occupied" error above never arrives as a surprise.

Re-run with -v to watch the compilers live instead of only seeing their output quoted on failure.

On this page