> ## Documentation Index
> Fetch the complete documentation index at: https://unkey.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Dockerfile builds

> Take full control over your container image with a Dockerfile. Configure the build context, use build-time secrets, and understand build caching.

<Info>
  Deploying applications on Unkey is in public beta. To try it, open the product switcher in the
  top-left of the dashboard and select **Deploy**. During beta, deployed
  resources are free. We're eager for feedback, so let us know what you think
  on [Discord](https://unkey.com/discord), [X](https://x.com/unkeydev), or
  email [support@unkey.com](mailto:support@unkey.com).
</Info>

By default Unkey [builds your application automatically](/builds/overview); you don't need a Dockerfile. When your build needs more control, for example system packages, custom build steps, or a toolchain detection doesn't cover, add a Dockerfile and Unkey builds with it instead.

If you're not comfortable writing a Dockerfile from scratch, the [AI Dockerfile prompt](/builds/dockerfile-prompt) generates one tuned for Unkey's runtime.

## Switching to Dockerfile builds

Configure the Dockerfile path in your [app settings](/platform/apps/settings#dockerfile). Unkey auto-detects Dockerfiles in your build context and offers them in the dropdown. Once a path is set, every deployment of that app and environment builds with the Dockerfile.

To switch back to automatic builds, set the Dockerfile field to **Automatic (no Dockerfile)**. Changes apply on the next deployment.

## Build configuration

| Setting            | Description                                                         | Default         |
| ------------------ | ------------------------------------------------------------------- | --------------- |
| **Root directory** | The build context directory, where `COPY` and `ADD` are relative to | `.` (repo root) |
| **Dockerfile**     | Path to the Dockerfile within the root directory                    | Automatic       |

See [App settings](/platform/apps/settings#build-settings) for the full reference.

## Build-time environment variables

Some builds need access to environment variables during the build step, for example to install private packages or generate code. All [variables](/platform/variables/overview) configured for the environment are available as Docker build secrets.

Unkey mounts all your variables as a `.env` file at `/run/secrets/.env` inside the build container. To use them, add a `--mount=type=secret` flag to the `RUN` step that needs them. Unkey exposes a build argument called `UNKEY_SECRETS_ID` that you reference as the mount's `id` (see [Variable changes and the build cache](#variable-changes-and-the-build-cache)).

Here's a complete example for a Node.js app that needs environment variables during the build step:

```dockerfile Dockerfile theme={"theme":"kanagawa-wave"}
FROM node:lts-alpine AS builder
ARG UNKEY_SECRETS_ID

WORKDIR /app
COPY . .
RUN npm install

# Mount the secrets file and load variables into the shell
RUN --mount=type=secret,id=${UNKEY_SECRETS_ID},target=/run/secrets/.env \
    set -a && . /run/secrets/.env && set +a && \
    pnpm build

FROM node:lts-alpine
WORKDIR /app
COPY --from=builder /app .
CMD ["node", "dist/index.js"]
```

Declare `ARG UNKEY_SECRETS_ID` inside every stage that mounts the secret. ARG values aren't inherited across stages, so each `FROM ... AS <stage>` that consumes variables needs its own declaration.

The secrets file uses standard `.env` syntax, one variable per line:

```bash /run/secrets/.env theme={"theme":"kanagawa-wave"}
DATABASE_URL=postgres://prod-db.acme.com/api
NPM_TOKEN=npm_abc123
FEATURE_FLAG=true
```

The `set -a && . /run/secrets/.env && set +a` pattern loads every variable from the file into the shell environment for that `RUN` step. The secret file is not persisted in the final image.

How you consume the file depends on your toolchain:

* **Tools that expect environment variables** (npm, pip, go): use the `set -a` pattern above to load them into the shell.
* **Frameworks that read `.env` files directly** (Node.js with dotenv, Ruby with dotenv): reference `/run/secrets/.env` in your build script instead of sourcing it.

### Why secret mounts instead of ARG or ENV?

Docker's `ARG` and `ENV` instructions are stored in the image layer history. Anyone with access to the image can extract them with `docker history` or `docker inspect`. Secret mounts avoid this problem: the file is available only during the `RUN` step and is never written to a layer.

### Variable changes and the build cache

`UNKEY_SECRETS_ID` is a hash of your project's variables. When you write `id=${UNKEY_SECRETS_ID}` on the mount line, BuildKit's cache key for that `RUN` includes the id, so any variable change produces a new id and a fresh execution of that step and everything after it in the same stage. Steps before the secret mount (base image pulls, dependency installs) keep caching normally.

## Troubleshoot Dockerfile builds

When a build fails, check the build logs in the **Deployments** tab. Common issues:

* **Missing Dockerfile**: Verify the Dockerfile path in your [app settings](/platform/apps/settings#dockerfile).
* **Dependency installation failures**: Check that your base image includes the tools your Dockerfile needs.
* **Context too large**: If your build context includes large files (node\_modules, data files), add a `.dockerignore` to exclude them.

## Next steps

<CardGroup cols={2}>
  <Card title="Generate a Dockerfile with AI" icon="wand-magic-sparkles" href="/builds/dockerfile-prompt">
    A prompt that produces a Dockerfile tuned for Unkey's runtime
  </Card>

  <Card title="App settings" icon="gear" href="/platform/apps/settings">
    Configure the Dockerfile path, root directory, and watch paths
  </Card>
</CardGroup>
