// for developers
Someone gave you a token. Now what?
You do not run the Oxid server — someone on your team does. This page is the whole of what you need: connect once, push a branch, get a URL, read the logs when it misbehaves. Nothing here requires access to the server itself.
# once, on your machine: oxid login http://oxid.tu-empresa.local:8080 → paste your token when prompted # then, from any checkout, forever: oxid up mi-rama oxid logs mi-rama
Connecting
oxid login saves the server and your token, checks both against the
daemon, and makes it active. From then on no command needs --api or
--token.
$ oxid login http://oxid.tu-empresa.local:8080 Access token (paste and press enter): •••• [+] Logged in to http://oxid.tu-empresa.local:8080 as `juan` (developer) [~] Projects: 1 — every other project answers 404 [~] Access expires: 2026-11-29 15:36:04 [~] You can: view environments and logs · deploy, pause, wake, destroy
The token is read from stdin rather than an argument, so it never lands in your shell
history or in the process list where anyone on a shared machine could read it with
ps. Pass --token instead when you are scripting.
| Command | What it does |
|---|---|
oxid login <url> | Save a server and log in. --as-name staging if you use more than one. |
oxid login | Log back in to the last server — the address is still saved, so you never re-type it. |
oxid logout | Clear the token, keep the server. What you want on a shared machine. |
oxid logout --forget | Remove the server entry too. |
oxid server | List saved servers; the active one is marked, tokens masked. |
oxid connect staging | Switch to another saved server. |
oxid whoami | Who you are here, and what you may do. |
Everything lives in ~/.config/oxid/config.toml, written 0600.
oxid context is the same thing with more knobs, if you prefer it.
What am I allowed to do?
Ask, instead of finding out from a 403 halfway through something:
$ oxid whoami [+] juan on http://oxid.tu-empresa.local:8080 (developer) [~] Projects: 1 — every other project answers 404 [~] Access expires: 2026-11-29 15:36:04 [~] You can: view environments and logs · deploy, pause, wake, destroy
| Your role | You can | You cannot |
|---|---|---|
viewer | See environments, logs and history. | Change anything. |
developer | Everything above, plus deploy, roll back, pause, wake and destroy environments. | Read or write secrets; change project settings. |
maintainer | Everything above, plus your projects' secrets, settings and branch rules. | Anything about the server itself. |
admin | The server too, and giving other people access. | — |
Two answers mean different things, and it is worth knowing which you got. A 403 tells you exactly what is wrong — your role is too low, your access expired, it was suspended — and is something an operator can fix for you. A 404 on a project means it is not in your scope; from where you stand it does not exist.
Getting a branch running
Usually you do not: someone wires a webhook once, and every push deploys its branch
by itself. oxid up is for the times you want it now, or the
branch is not one the webhook rules cover.
$ cd ~/code/tienda && git checkout -b feature-carrito $ oxid up feature-carrito [>] Building image for feature-carrito... [+] Image built (cache hit: 100%, 832ms) [+] Environment live at: http://feature-carrito.tienda.local.dev/
The daemon clones the repository itself, from your checkout's origin.
It never reads your working tree — uncommitted work is not deployed, which is
usually what you want and always worth knowing.
Asking explicitly always wins. If your team restricted which
branches deploy on push, oxid up <branch> still deploys the branch
you name. The filter is about what a push does, not about what you may ask
for.
Reading logs, and working out what happened
$ oxid logs feature-carrito # what the container printed $ oxid logs feature-carrito --follow # and keep printing $ oxid logs feature-carrito --tail 200
Where to look, by what you are actually asking:
| The question | The command |
|---|---|
| Is my branch up, and on what URL? | oxid status |
| What is my app printing? | oxid logs <branch> |
| Why did my deploy fail? | oxid logs <branch> — a failed build leaves a build_failed environment whose logs are the build output. |
| Who deployed this, and when? | oxid audit --branch <branch> |
| Is it just waiting for capacity? | oxid queue |
| Is it me, or the server? | oxid doctor |
States you will see
| State | Means |
|---|---|
building | The image is being built. First build of a branch is the slow one; after that the cache does most of the work. |
running | Live and serving. |
paused | Nobody used it for a while, so it was stopped and its memory given back. The next request wakes it — you do not have to do anything. oxid wake <branch> if you want it warm first. |
build_failed | Your build or first start broke. The previous working environment, if any, is still serving — a broken push does not take the branch down. |
destroyed | Gone: the branch was deleted, its lifetime ran out, or someone tore it down. |
A paused environment answering slowly on the first request is normal, not a bug: it is the container starting. That is the whole point of scale-to-zero — your idle branches are not holding the server's RAM.
The rest of the day-to-day
$ oxid status # your branches, states and URLs $ oxid ps # projects you can see $ oxid pause feature-carrito # give the RAM back now $ oxid wake feature-carrito # warm it before a demo $ oxid down feature-carrito # destroy it for good $ oxid rollback feature-carrito --commit a1b2c3d $ oxid audit --branch feature-carrito
Every command takes --json and exits with a distinct code per failure
kind, so any of this drops into CI without parsing text.
Prefer a browser? The same server serves a dashboard at its root. Paste your token into the box in the top bar and you get the same view, plus live logs. It installs as an app and opens offline — see Web dashboard.
Changing how your branch is built
Most repositories need nothing: if yours has a Dockerfile it is used,
and if it does not, Oxid reads your package.json, go.mod,
pyproject.toml or Cargo.toml and generates one — see
Stacks & builds.
When you do need to say something, it goes in oxid.toml at the root of
your repository, and it is read from the commit being deployed. So
you can change it on your branch and see the effect on your branch alone:
[build] dockerfile = "docker/Dockerfile.dev" context = "." on_start = ["./seed.sh"] # runs inside the container once it is up [routing] port = 3000 # the port your app listens on
The base domain and the idle/lifetime policy are not yours to change from a branch — otherwise one branch could rewrite another's URL. Those belong to whoever runs the server.
When something is off
| What you see | What it is |
|---|---|
403 … needs the `maintainer` role | Your role is below the action. Ask an operator; nothing is broken. |
403 … this access expired | Your token ran out. An operator issues a new one. |
403 … has been suspended | Your access was switched off. It can be switched back on with the same token. |
404 project … | Not in your scope. From where you stand it does not exist. |
401 missing or invalid bearer token | Not logged in, or an OXID_TOKEN in your shell is overriding the saved one. oxid whoami says which server you are on. |
cannot reach daemon | Wrong address, or the server is down. oxid server shows what you are pointed at; oxid doctor checks the rest. |
| Your branch deployed nothing on push | Your team may have restricted which branches deploy. oxid up <branch> still works, and oxid audit shows what happened. |
| The URL is slow the first time | The environment was paused and is waking. Normal. |