Skip to main content
zenith up uploads your local project and launches a temporary deployment for testing. It builds your app on Zenith and returns a public URL. It does not submit your app for publication or create a subscription. Install the CLI and sign in first. Run the commands below from your app’s root directory.

Prepare the app

Review your root Dockerfile and zenith-compose.yml. The preview policy supports:
  • Exactly one app service built with build: . and the root Dockerfile. Do not also set image on this service.
  • Dependencies using public container images.
  • An HTTP app listening on 0.0.0.0, exposed through a primary x-zenith.expose entry with web: true and no label. The Dockerfile can omit EXPOSE.
  • Named volumes and dependencies declared with depends_on.
Bind mounts, external configuration files, remote build contexts, alternate Dockerfiles, and build arguments, targets, or platforms fail preview validation. Host environment variables are not available to Compose interpolation. The CLI also rejects privileged: true and inline secret content. Use .env.local for private test credentials. Use x-zenith.env, x-zenith.storage, and x-zenith.configs in previews as well as published apps. Compose interpolation uses an empty host environment. Write $$ for a literal dollar sign. Use platform mappings for generated values, SMTP, and OIDC credentials. Keep other test secrets in .env.local. Use the Compose reference for the shared contract and preview constraints. Run zenith check before uploading. Zenith validates the project again after upload.

Supply test secrets

Put local test secrets in a gitignored .env.local at the project root. Do not put them in the Compose file, Dockerfile, or committed source.
.env.local
zenith check validates .env.local separately. zenith up sends the values separately from the source archive. The file must be valid UTF-8 and can contain up to 64 variables and 32 KiB of data. Reserved variable names are rejected. Other environment files are not loaded as test secrets.
Use test credentials and test data. Anyone with the deployment URL can reach the app. Configure app authentication if the test data needs access control.

Launch a temporary deployment

The CLI checks your project, uploads it, waits for the build, and prints the URL, session ID, and teardown time when the app is ready. The upload uses your local files, including eligible uncommitted changes. It does not require a public repository or a Git push. The queue estimate predicts when the build may start. Build and deployment time follow. Open the returned URL. Test the app’s main flows, including sign-in, writes, and any background work it needs.

Lifetime and replacement

A preview lasts 20 minutes from readiness by default. Use the teardown time printed by the CLI because the service can limit the lifetime. Queue and build time do not consume the ready lifetime. Treat preview data as temporary. Each account has one live preview. A new preview of the same repository replaces the old one only after the new one is ready. To replace a preview from another repository, pass its session ID explicitly:
Closing the CLI cancels a queued preview. A build that has already started continues. A ready preview stays live until expiry or zenith down.

Upload limits

Uploads are limited to 100 MiB compressed and 200 MiB expanded. File selection combines .gitignore with Dockerfile.dockerignore, or .dockerignore when no Dockerfile-specific ignore file exists. Required build and ignore files are retained. Git metadata, node_modules, private-key patterns, and environment files are excluded. The templates .env.example, .env.sample, and .env.template remain eligible for upload. Review your project before uploading. Ignore rules are not a substitute for checking that source files contain no secrets.

Inspect logs and failures

Without a session ID, logs uses the last session for the current project and Zenith address. The default source is all. The default runtime tail is 200 lines. Pass a session ID to inspect a specific deployment:
If validation fails, fix the reported Dockerfile, Compose, environment, or archive issue before retrying. If the app fails to become ready, inspect build and runtime logs. Confirm that its process stays running and listens on the declared port at 0.0.0.0. up stops waiting after 300 seconds without new build output by default. To allow a longer idle period:
The timeout changes how long the CLI waits for new output. The deployment lifetime stays the same. A timeout does not stop a build that has already started. Use the printed session ID to inspect logs or request cleanup.

Stop the deployment

Without a session ID, down selects the last session for the current project. To stop a specific session:
Cleanup runs in the background. If cleanup fails, repeat zenith down with the same session ID.
Testing is complete when the app’s required flows work at the returned URL, you have checked the runtime logs, and you have requested cleanup or recorded the expiry time. Keep the tested commit and any local changes in your test notes.

Next: publish your app

Submit a public GitHub commit and marketplace listing for review.