Environment variables & secrets
Give your app its settings and secrets — add them in the Configuration tab or the CLI, keep the sensitive ones masked, and apply changes without a full rebuild.
Most apps need a few pieces of information to run: a database address, an API key, a "am I in production?"
flag. Those are environment variables — little named settings your app reads when it starts. Think of
them as sticky notes you hand your app: DATABASE_URL = ..., STRIPE_KEY = .... Openship keeps those notes
for you, hands them to your app every time it builds and runs, and hides the sensitive ones so nobody can
read them over your shoulder.
What you need first
- A project you've already created in Openship (if not, start with Deploy from GitHub).
- The names and values you want to set — for example
DATABASE_URLand its connection string. - Nothing else. Openship encrypts and stores the values for you.
Add or edit variables in the dashboard
Open the Configuration tab
Go to your project and open the Configuration tab. Find the Environment variables card and press Edit. A panel opens showing the variables you already have (empty is fine — a brand-new app often has none).
Add a variable
Press Add variable. You get a row with two boxes: the KEY on the left (the name, like DATABASE_URL)
and the value on the right. Type both.
Add as many rows as you need. To remove one, press the trash icon at the end of its row.
Mark the secret ones
Some values are sensitive — passwords, API keys, tokens. For each of those, press the key icon on the
row to mark it as secret. A secret's value is stored the same way, but from then on it shows as dots
(••••••••) instead of plain text, so it stays hidden whenever you reopen the editor.
Environment values are encrypted at rest
Whether or not you mark a variable secret, Openship encrypts every value before saving it. Marking a value secret adds the on-screen masking on top — it controls what you can see later, not whether it's protected on disk.
Inline service environment values and build arguments are also encrypted, including their copies in
saved deployment snapshots and Compose drift baselines. Existing plaintext service configuration is
converted when the API or native engine starts after upgrading. Keep your BETTER_AUTH_SECRET with
your database backup: it is needed to read these values. To downgrade to a version from before this
protection, restore its matching database backup as well.
When moving to an installation with a different key, use Settings → Data Transfer with secrets included. It re-encrypts the configuration for the destination. Transfers or recovery manifests that omit secrets also omit inline environment, build arguments and protected service configuration; set those values again before deploying.
Save
Press Save changes. Openship only writes the rows you actually added, changed, or deleted — every other variable is left exactly as it was. That's why a masked secret you didn't touch is never overwritten: you never re-typed it, so it's never re-sent.
Saving isn't the same as applying
A saved change is stored right away, but the running app keeps its old values until the next deploy. If something is already live, Openship offers a shortcut to push the change out immediately — see Apply without a full rebuild below. Otherwise the new values take effect the next time you deploy.
When your app sees these values
Project-level variables are available at two moments:
- During the build — so a value baked in at build time (for example a
NEXT_PUBLIC_...setting in a frontend) is there when the build runs. - At runtime — so your running server can read them the normal way (like
process.env.DATABASE_URL).
For a Dockerfile build, declare every value you consume with ARG (and copy it into ENV only when the
running image also needs it):
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
RUN npm run buildThe project environment is the shared build/runtime layer. A multi-service project's services[].env
is different: it belongs only to that service at runtime and is never leaked into an image build. In
openship.json, add services[].buildArgs when an image needs an explicit build-only value or when you
want to document which shared key it inherits:
{
"env": { "NEXT_PUBLIC_API_URL": "https://api.example.com" },
"services": [
{
"name": "web",
"build": ".",
"buildArgs": { "NEXT_PUBLIC_API_URL": null, "BUILD_FLAVOR": "production" }
}
]
}Here null means “inherit the same-named project variable”; a string is a per-image override. Values
declared in top-level openship.json.env become active project defaults automatically. A generic .env
file is only used after you choose Import .env.
Docker build arguments are not secret storage
Build arguments can remain visible in image metadata or build cache. Prefer runtime environment
variables for credentials. If a build genuinely needs a secret, use a dedicated BuildKit secret
flow rather than committing it to openship.json or baking it into the image.
Service overrides and credential rotation
Open Services → select a service → Environment to see its effective saved variables. The list includes Compose values, shared project variables and explicit service overrides, with a source label on each row. Openship stores these values; the list remains available when the deployment server is offline.
Editing an inherited value creates an override for that service. Saving changes only the rows you edited; it does not copy the other inherited values into overrides. Removing an override restores the inherited value, if one exists. Remove inherited keys at their Compose or project source. Conflicting edits from another session are rejected before anything is saved.
On a normal service deployment, the highest-priority value wins in this order:
- A service-scoped variable from its environment editor.
- A literal in that service's Compose
environmentoropenship.jsonenvmap. - The project's environment, captured when the deployment starts.
Compose expressions such as TOKEN: ${TOKEN} resolve against the configured values;
they do not pin a previous scan's value. A rollback instead replays its captured
project values, including their precedence over present-day service overrides.
openship project env set warns when a changed or deleted key still has a service
override. The API and SDK return the same warnings array, and deployment logs name
keys whose service values win. These messages contain names only. Saving the project
value succeeds, but it cannot replace a service-owned credential. Update the service
value, or remove its override to inherit the project value, then deploy. Deleting a
project variable does not delete a service's copy.
For example, if web pins TOKEN=old, setting the project's TOKEN=new will warn
about web; a rebuild alone still uses the pinned value. In the service editor,
remove that override before relying on the project's rotated token.
Reveal, hide, and replace a secret
Inside the editor, each value has an eye icon to show or hide it. A secret you saved earlier comes back
masked with the placeholder •••••••• (set — type to replace). To change it, just type the new value over
the dots. To keep it, leave it alone — Openship keeps the stored value untouched.
Production and preview values
Openship keeps variables per environment, so your test setup and your live setup can differ (a preview
build can point at a test database while production points at the real one). The three environments are
production, preview, and development.
The project editor manages production values. A service's Environment tab uses
its active deployment's environment, or production before the first deployment.
The CLI also supports preview and development through --environment.
These are variable sets within a project. Runtime isolation comes from selecting a separate
non-production project environment and deploying its project ID. Passing --env preview against
a production project is rejected; it cannot promote that preview onto the production runtime.
See preview deployment for the complete flow.
Download environment variables
In a service's Environment tab, choose Download .env beside Upload .env. The file contains the listed variables and their real saved secret values. Downloading does not reveal those secrets in the editor, save edits, or restart the service. Unsaved edits shown in the editor are included in the download.
The file uses Compose-compatible .env quoting. Upload .env restores its literal
values, including dollar signs, quotes, and multiline values, without expanding variable references.
Apply without a full rebuild
Rebuilding an app just to change a setting is slow — nothing about your code changed. So when you save an env change and the project is already deployed, the editor shows an Apply (restart, no rebuild) button.
Press it and Openship recreates the running container from the image it already built, with the new values injected. No git clone, no build — just a quick restart. It's the fastest way to roll out a changed key or a rotated secret.
From the terminal, openship deploy --refresh (shown below) applies environment
changes through a deployment without rebuilding.
For one service, open its Environment tab, press Save, then
Apply environment changes in the toolbar above the variables. It refreshes only
that service using the image already running on its target. The editor stays open
and shows completion after the service starts. This is a dedicated service action
(POST /api/projects/:id/services/:serviceId/apply-env); it creates no deployment or
build session. Docker gets a graceful stop, and the replacement retains the existing
ports, project network address, volumes, commands, and resource limits. If startup
fails, Openship restores the previous container and leaves the changes pending.
The toolbar offers Apply only when a comparison with the deployed container finds
saved changes, including removed variables. Check running service refreshes
that comparison. An unavailable server is reported as an unknown state, while the
saved variables remain editable.
For an older or migrated service, Docker may still hold variables that were never saved in Openship. Recover from running service reads those missing values from that service's container, excluding image defaults, and adds them to the editor for review. Press Save to store them encrypted in Openship. Recovery never overwrites an already saved value. Before applying, recover these values or explicitly choose to remove them from the running service.
This action supports Docker services on a server or an Openship Cloud Docker workspace. Legacy cloud workspaces and adopted containers on Docker's default bridge require Redeploy. Namespace-sharing services must be refreshed together through a deployment.
A normal Restart keeps the container's existing variables. When saved changes are pending, Openship opens the service's Environment panel so you can apply them there. Variables used during a build still require a rebuild.
CLI
Everything above works from the CLI. Secret values always come back masked when you list them.
# List a project's variables (secrets show masked)
openship project env get <project-id>
# Set one or more values (repeat --set for each)
openship project env set <project-id> --set DATABASE_URL=postgres://... --set LOG_LEVEL=info
# Mark the values in this command as secret
openship project env set <project-id> --set STRIPE_KEY=sk_live_... --secret
# Remove a variable
openship project env set <project-id> --unset OLD_FLAG
# Target a different environment (defaults to production)
openship project env set <project-id> --environment preview --set API_URL=https://staging.example.com
# Push the current env to the running app — no git pull, no rebuild
openship deploy --refreshenv set merges: it only touches the keys you name with --set and --unset, leaving everything else
in place.
For a multi-service (compose) project, each service has its own variables. Target the stack with
-p and the service by name:
# List a service's variables (secrets masked)
openship service env get web -p my-stack
# Set values for a service (KEY=VALUE pairs)
openship service env set web -p my-stack DATABASE_URL=postgres://... --secret
# Pick the environment (defaults to production)
openship service env set web -p my-stack -e preview API_URL=https://staging.example.comSecrets and service env
The service command writes the whole environment at once, so it first reads the current values and
merges yours in. Because saved secret values can't be read back, if the service already has a
secret you didn't re-type, the command stops and asks you to re-specify it — or pass --replace
to drop every value that isn't in your command.
Troubleshooting
I saved a variable but my app still doesn't see it
Saving stores the value; the running app only picks it up on a deploy. Use Apply (restart,
no rebuild) (or openship deploy --refresh) to push it out now, or just redeploy.
A secret shows as dots and I can't read it back
That's on purpose — Openship never reveals a stored secret's value again, in the dashboard or the CLI. If you need to change it, type a new value over the dots. If you've lost the original, set a fresh one.
The build failed with a missing-variable error
Your app expected a variable that isn't set yet. Add it in the Configuration tab (or with
openship project env set), make sure the name matches exactly — env names are case-sensitive —
then deploy again. See Troubleshooting → Deployments for
more.
Related guides
Deploy with openship.json
Add a declarative openship.json to your repo so Openship builds and deploys it the same way every time — in the wizard and headlessly on push.
Custom domains, DNS & SSL
Add custom and wildcard domains, point DNS at your app, and set up HTTPS with a connected provider or manual TXT verification.