dibbla deploy & apps
Build the current directory as a container, push it to the Dibbla platform, and manage the resulting application — env vars, replicas, CPU, memory, port, access policy.
dibbla deploy packages a directory containing a Dockerfile and ships it to your Dibbla organization. The resulting app is reachable at https://<alias>.dibbla.com.
dibbla apps is the CRUD surface for already-deployed apps: list them, change their config, or delete them. Application checks live on dibbla apps checks. The maintenance agent and the change queue live on dibbla apps maintenance and dibbla apps proposals.
dibbla deploy
Build and push the contents of [path] (defaults to .) as a Dibbla application.
Requirements
- A
Dockerfileat the deploy root. - The Dockerfile must expose a port and define an entrypoint.
- Authentication via
dibbla loginorDIBBLA_API_TOKEN. REVIEW.mdat the deploy root, and a handbook atdocs/index.md(orAPP.md) whose frontmatter carries asubtitle:— non-empty, not placeholder text, and 140 bytes or fewer.
The last one is a client-side gate: dibbla deploy checks for both files and
exits 1 before uploading anything. --skip-review bypasses it. See
Deploy your first app for what belongs in each file.
Symlinks inside the deploy directory are followed and packaged as regular files. Symlinks whose target escapes the deploy root (including absolute symlinks like /etc/passwd) are skipped — you can’t accidentally upload host files.
The rest of the directory is packaged, but not all of it survives to the build. See what reaches the build below.
Flags
| Flag | Purpose |
|---|---|
[path] (positional) | Directory to deploy. Default: .. |
-a, --alias <name> | Custom app alias. Default: directory name. The alias becomes the subdomain. |
-f, --force | Recreate an existing alias after a successful build (brief restart). A failed build leaves the running app untouched. Mutually exclusive with --update. |
-u, --update | Rolling update of an existing alias — zero downtime. |
-e, --env KEY=value | Set a plain env var — a setting, not a secret. Repeatable. Overrides --env-file per key. A name or value that looks like a secret is refused; see env vars that look like secrets. |
--env-file <path> | Load plain env vars from a .env-style file. The file is the base layer; -e overrides individual keys. See env precedence and .env file format. A file of keys goes in with secrets import instead. |
--allow-secret-env | For a person whose env var only looks like a secret: send it anyway. Never covers a name that is one of the app’s secrets, and an AI assistant never passes it. |
--cpu <value> | CPU request, e.g. 500m or 1. |
--memory <value> | Memory request, e.g. 512Mi or 1Gi. |
--port <value> | Container port the app listens on. |
--favicon <url> | Favicon URL shown in the Dibbla dashboard and browser tab. |
--require-login | Require authenticated access. |
--access-policy <value> | all_members or invite_only. Effective when --require-login is set. (email_domain needs a domain list, which no flag supplies — set it in the console.) |
--google-scopes <scope> | Additional Google OAuth scope. Repeatable. |
-m, --message <text> | Deploy message — used as the VCS commit subject in your app’s deploy history. |
--microsoft-scopes <scope> | Additional Microsoft OAuth scope. Repeatable. |
--skip-review | Skip the REVIEW.md + handbook gate. |
--target-env <name> | Deploy to a named target environment. |
--profile <name> | Use a named resource profile. |
--no-public | Do not expose the app publicly. |
--verbose-build | Stream full build output. |
-q, --quiet | Print only the URL on success. Mutually exclusive with --json. |
--json | Print the JSON response body. Mutually exclusive with --quiet. |
Examples
# Deploy current directory using its name as the alias $dibbla deploy -m "feat: initial deploy" [info] deploy deployment_id=dep_wuk1bfahjdua [info] build step=13/23 done name=go-build elapsed=6.5s [info] rollout phase=rollout-start strategy=create [info] rollout phase=route-done [info] deploy status=ok url=https://hello-world-b4687da9.dibbla.com elapsed=19.7s deploy ok · https://hello-world-b4687da9.dibbla.com · 19.7s
# Plain settings only, kept outside the deploy root — see the guardrail note below $dibbla deploy . \ --env-file ../config/app.env \ -e LOG_LEVEL=debug \ -m "feat: initial deploy" # The file seeds every var; -e wins for LOG_LEVEL
$dibbla deploy ./api \ --alias my-api \ --cpu 500m --memory 512Mi --port 3000 \ -e NODE_ENV=production -e LOG_LEVEL=info \ -m "feat: add /healthz endpoint"
# Zero-downtime redeploy of an existing alias $dibbla deploy --update -m "fix: correct the totals query" [info] rollout phase=rollout-start strategy=rolling [info] deploy status=ok url=https://my-api-b4687da9.dibbla.com elapsed=24.1s
# Recreate an existing alias after a successful build (brief restart) $dibbla deploy --force --alias my-api -m "chore: rebuild from scratch" [info] rollout phase=rollout-start strategy=replace
These transcripts are the non-interactive form — one structured line per
event — which is what you get in CI or when piping. In an interactive
terminal the CLI renders a live step table under BUILD, DEPLOYED and
SERVICES headers instead. Same events, different presentation.
--force builds and pushes the new image first and only then replaces the
existing deployment, so there is a brief restart while the new pod comes up.
If the build fails (a broken Dockerfile, a registry or builder outage) the
command returns an error and the running app is left exactly as it was — see
when a build fails. Use --update for zero-downtime
rolling updates of an alias that already exists. The two flags are mutually
exclusive.
When a build fails
Every deploy builds and pushes the new image before it touches anything that is running, so a failed build never takes your app down. The error code tells you whose problem it is, and the exit code lets a CI job tell the two apart without parsing text:
| Code | HTTP | Exit | Meaning | What to do |
|---|---|---|---|---|
BUILD_FAILED | 500 | 2 | A step in your build failed. The failing step and the build log tail are in the output. | Fix the Dockerfile or the source and deploy again. |
REGISTRY_UNAVAILABLE | 503 | 20 | Dibbla’s container registry answered an error, ran out of disk or did not answer while the image was pushed. | Nothing on your side needs to change. Wait a few minutes and deploy again; contact support if it persists. |
BUILD_SERVICE_UNAVAILABLE | 503 | 20 | Dibbla’s build service could not be reached. | Same as REGISTRY_UNAVAILABLE. |
The two 503 codes are platform failures: the message says so explicitly and
confirms that your existing app was not touched. dibbla deploy --follow, the
--json and CI log modes, and the platform_operation MCP tool all report the
same code. Any other error (ALIAS_EXISTS, validation, authentication) exits
1.
.dibblaignore
The platform keeps a server-side version-controlled history of every deploy. Use a .dibblaignore at the deploy root to filter what’s committed.
.dibblaignore governs this history and nothing else. Adding a path to it does not remove that path from the Docker build, and leaving a path out of it does not put the path in the build either — a separate filter decides that, and .dibblaignore has no influence over it.
The syntax is gitignore-style — **, directory globs, and negation all work.
build/
dist/
*.tsbuildinfo
coverage/
.nyc_output/
.env
.env.local
.vscode/
.idea/
*.swp
.DS_Store
data/*.parquet
fixtures/*.bin Regardless of .dibblaignore, the platform keeps a short built-in denylist out
of the managed repository: environment files, the most common key and
certificate extensions, and the usual dependency and build-output directories.
A hit here is filtered with a warning, not rejected — the deploy proceeds
without the file, and the warning names what was dropped. Only the size caps
stop a deploy outright.
The list is not written out here on purpose. It lives in the platform, it can
change, and a copy in this page would eventually be a copy that lies. What is
worth knowing is its shape: it matches whole names and extensions, so a
secret stored under an unusual name is not caught. A private key saved as
deploy_key or server-cert.txt matches no pattern and lands in the
repository. (The four conventional SSH key names — id_rsa, id_ed25519,
id_ecdsa, id_dsa — are a separate case: the CLI drops those before the
upload leaves your machine, so they never reach the filter at all.) Do not
treat any of this as a safety net; it is a backstop for the two or three most
common accidents.
--env-file reads the file client-side and sends the values over the
authenticated API — the file is never packaged into the upload at all, so the
question of what reaches the build or VCS never arises. That is safe. What is
not safe is a .env sitting in the directory you deploy: that is a
pre-deploy guardrail blocker, it is stripped from VCS regardless, and being
stripped from VCS does not mean it is absent from the build context.
Keep the file outside the deploy root and point at it by path:
dibbla deploy . --env-file ../config/app.env -m "feat: initial deploy"--env-file makes plain env vars, which anyone who can read the app’s
configuration can read. A file of keys and passwords is refused here — load
it with dibbla secrets import ../secrets/.env.prod -d <alias> and deploy
without it.
Per-file and per-commit size limits are enforced server-side; oversize files cause the deploy to fail with an ErrCodeVCSFiltered error.
What reaches the build
The upload is filtered on its way to docker build, and this is the filter that
produces build failures rather than warnings.
The rule: your build context is the deploy directory minus a set of
regenerable directories. Dependency trees and build outputs — the things a
build step produces — are dropped during extraction and are not present
when your Dockerfile runs. Treat them as absent and produce them in the
build.
Three properties worth internalising, because each one costs someone an afternoon:
- It is silent. No warning, no
vcs_filteredentry, nothing in the build log. The first sign is aCOPYfailing on a directory you can see in your own working tree. .dibblaignoreand.dockerignorehave no bearing on it, in either direction. There is no opt-out.COPY --from=<stage>is unaffected. It reads from an earlier build stage, not from the upload — which is exactly why it is the fix.
In practice this means writing your Dockerfile the way a clean CI checkout
would need it anyway:
# ✗ Builds locally. Fails here: the directory was not uploaded.
COPY vendor/ ./vendor/
RUN go build -mod=vendor -o /app ./cmd/server
# ✓ Regenerate it in the build.
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o /app ./cmd/server
# ✓ Node: build in a stage, then COPY --from= it.
FROM node:20 AS build
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
The same shape applies to Python (install requirements in the build rather than shipping a virtualenv) and to Next.js (run the build rather than shipping its output directory).
The exact set is a platform detail that can change, so it is not copied here.
If a deploy fails with BUILD_FAILED on the copy-source step and a message
ending "/vendor": not found — naming a directory that plainly exists in your
own working tree — this is why. The fix is always the same: build it instead of
shipping it.
dibbla apps list
Print every deployed app in the org with its URL, status, and last deploy time.
$dibbla apps list 🌱 Retrieving Dibbla applications... Found 3 applications: ALIAS URL STATUS LAST DEPLOYED ----- --- ------ ------------- my-api https://my-api.dibbla.com running 2026-04-28 14:02:11 ops-tool https://ops-tool.dibbla.com running 2026-04-27 09:14:38 billing https://billing.dibbla.com sleeping 2026-04-16 17:30:22
dibbla apps get
Show the deployment record for one app: URL, status, size, health check, login policy and — for multi-service deployments — the per-service breakdown. This is the command dibbla logs --pod-stream errors point at when no pods match a service.
| Flag | Purpose |
|---|---|
<alias> (positional, required) | App to show. |
--json | Print the raw API document. |
$dibbla apps get my-api 📦 my-api — https://my-api.dibbla.com Status: running Deployed: 2026-04-28 14:02:11 Updated: 2026-04-28 14:02:11 Replicas: 2 Size: 500m CPU / 512Mi memory Health: healthy (42ms) Login: required (all_members) Services (2): web running 2/2 ready worker running 1/1 ready (stateful)
$dibbla apps get my-api --json | jq '.services[].name' dibbla apps update
Change the configuration of a deployed app without a fresh deploy. At least one flag is required.
Flags
| Flag | Purpose |
|---|---|
<alias> (positional, required) | Target app alias. |
-e, --env KEY=value | Set a plain env var — a setting, not a secret. Repeatable. Overrides --env-file per key. A name or value that looks like a secret is refused; see env vars that look like secrets. |
--env-file <path> | Load plain env vars from a .env-style file. The file is the base layer; -e overrides individual keys. See env precedence and .env file format. A file of keys goes in with secrets import instead. |
--allow-secret-env | For a person whose env var only looks like a secret: send it anyway. Never covers a name that is one of the app’s secrets, and an AI assistant never passes it. |
--replicas <n> | Desired number of replicas. |
--cpu <value> | CPU request/limit, e.g. 500m, 1. |
--memory <value> | Memory request/limit, e.g. 256Mi, 512Mi. |
--port <n> | Container port (1–65535). |
--favicon <url> | Favicon URL. Use "" to clear. |
--require-login true|false | Toggle authenticated access. |
--access-policy <value> | all_members, invite_only, or "" to clear. |
--google-scopes <scope> | Repeatable. Use "" to clear. |
Examples
$dibbla apps update my-api -e NODE_ENV=production --replicas 2 ✏️ Updating deployment 'my-api'... ✅ Deployment updated successfully. Alias: my-api URL: https://my-api.dibbla.com Status: running Health: ok (398ms)
$dibbla apps update my-api --cpu 500m --memory 512Mi --port 3000 $dibbla apps update my-api --require-login true --access-policy invite_only dibbla apps restart
Trigger a rolling restart of one service, without redeploying. This is how a changed secret reaches running pods — saving a secret updates the store, but a container reads its environment only at start.
| Flag | Purpose |
|---|---|
<alias> (positional, required) | App to restart. |
-s, --service <name> | Required. Service to restart. For a single-service app the conventional name is app; for a manifest deploy, the name as it appears in dibbla.yaml. |
-q, --quiet | Print only the alias on success. |
--json | Print the JSON response body. |
Idempotent in the sense that it always succeeds — but not a no-op: calling it twice produces two pod rollouts.
# single-service app $dibbla apps restart my-app --service app # one service of a multi-service app $dibbla apps restart my-app -s worker
dibbla apps delete
Permanently delete an app. The alias becomes available for reuse.
| Flag | Purpose |
|---|---|
<alias> (positional, required) | App to delete. |
-y, --yes | Skip the confirmation prompt. |
$dibbla apps delete my-api 🗑️ Attempting to delete application 'my-api'... ? Are you sure you want to delete 'my-api'? This action cannot be undone. (y/N) ✅ Application 'my-api' deleted successfully
See also
dibbla secrets— anything sensitive: a secret is write-only and never goes through-e. Set one at a hidden prompt, request it with a link, or bulk-load a whole file withsecrets importwithout redeploying.dibbla db— provision a Postgres and bind aDATABASE_URLsecret to your app.dibbla run— run adibbla-task.yamlpipeline locally before you deploy.