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

# Docker Deployment

> Guide to building and deploying a Backstage backend Docker image, covering the generated Dockerfile, build steps, BuildKit requirements, and CI/CD considerations.

This guide shows how to package a Backstage backend into a Docker container so you can run it locally or deploy it with your preferred orchestrator (for example, Kubernetes or Amazon ECS). It walks through the generated backend Dockerfile, local preparation steps, image build and run commands, and CI/CD considerations.

Key terms: Backstage Docker image, Docker BuildKit, Yarn v3 (Berry), backend bundle, CI/CD build agents.

<Callout icon="lightbulb" color="#1CB2FE">
  Before building, make sure you understand where the Docker build context should be. The Dockerfile expects the backend bundle artifacts under `packages/backend/dist` in the build context (usually the repository root).
</Callout>

## Where the Dockerfile lives

When you create a Backstage app using `backstage create-app`, a production-ready Dockerfile is generated for the backend package.

Dockerfile path:
`packages/backend/Dockerfile`

Below is the generated Dockerfile (unchanged):

```dockerfile theme={null}
FROM node:20-bookworm-slim
# Set Python interpreter for `node-gyp` to use
ENV PYTHON=/usr/bin/python3
# Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend.
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    apt-get update && \
    apt-get install -y --no-install-recommends python3 g++ build-essential && \
    rm -rf /var/lib/apt/lists/*
# Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image,
# in which case you should also move better-sqlite3 to "devDependencies" in package.json.
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    apt-get update && \
    apt-get install -y --no-install-recommends libsqlite3-dev && \
    rm -rf /var/lib/apt/lists/*
# From here on we use the least-privileged `node` user to run the backend.
USER node
# This should create the app dir as `node`.
# If it is instead created as `root` then the `tar` command below will fail: 'can't create directory `packages/`: Permission denied'.
# If this occurs, then ensure BuildKit is enabled ('DOCKER_BUILDKIT=1') so the app dir is correctly created as `node`.
WORKDIR /app
# Copy files needed by Yarn
COPY --chown=node:node .yarn ./.yarn
COPY --chown=node:node .yarnrc.yml ./
COPY --chown=node:node backstage.json ./
# This switches many Node.js dependencies to production
ENV NODE_ENV=production
# This disables node snapshot for Node 20 to work with the Scaffolder.
ENV NODE_OPTIONS="--no-node-snapshot"
# Copy repo skeleton first, to avoid unnecessary docker cache invalidation.
# The skeleton contains the package.json of each package in the monorepo,
# and along with yarn.lock and the root package.json, that's enough to run yarn install.
COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./
RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz
RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \
    yarn workspaces focus --all --production && rm -rf "$(yarn cache clean)"
# This will include the examples, if you don't need these simply remove this line
COPY --chown=node:node examples ./examples
# Then copy the rest of the backend bundle, along with any other files we might want.
COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./
RUN tar xzf bundle.tar.gz && rm bundle.tar.gz
CMD ["node", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.production.yaml"]
```

## Prepare the repository (local or CI)

Before running a Docker build, produce the backend artifacts the Dockerfile expects. Run these steps locally or replicate them in your CI pipeline.

1. Install dependencies

* Use Yarn v3+ (Backstage uses Yarn Berry). Install in immutable mode so the lockfile is enforced:

```bash theme={null}
yarn install --immutable
```

2. Generate TypeScript types

* Compile or type-check to ensure any generated types are available:

```bash theme={null}
yarn tsc
```

3. Build the backend bundle

* Produce the `bundle.tar.gz` and `skeleton.tar.gz` artifacts under `packages/backend/dist`.

Option A — build the whole monorepo (recommended):

```bash theme={null}
yarn build
```

Option B — build only the backend package:

```bash theme={null}
# Use your workspace name if different, e.g.:
yarn workspace @backstage/backend build
```

After these steps confirm:

* `packages/backend/dist/bundle.tar.gz`
* `packages/backend/dist/skeleton.tar.gz`

exist in your repo root (or in the CI build context).

## Important: Docker BuildKit

<Callout icon="warning" color="#FF6B6B">
  Make sure Docker BuildKit is enabled when building this Dockerfile (see [https://docs.docker.com/develop/develop-images/build\_enhancements/](https://docs.docker.com/develop/develop-images/build_enhancements/)). BuildKit is required for the `--mount=type=cache` and certain ownership behaviors used in the Dockerfile. You can enable it by setting `DOCKER_BUILDKIT=1` in your build environment.
</Callout>

BuildKit is required for mount caching and for correct ownership handling that the Dockerfile relies on. In CI, enable BuildKit or use a builder (kaniko/buildah) that supports these Dockerfile features.

## Build the Docker image

From the repository root (so the `packages/backend/dist` artifacts are in context), run:

```bash theme={null}
DOCKER_BUILDKIT=1 docker build -f packages/backend/Dockerfile -t backstage:latest .
```

Notes:

* `-f packages/backend/Dockerfile` specifies the Dockerfile path.
* The final `.` is the build context (typically the repo root).
* `DOCKER_BUILDKIT=1` enables BuildKit features.

## Run the container locally

By default the Backstage backend listens on port 7000. Run the container and map the port:

```bash theme={null}
docker run --rm -p 7000:7000 backstage:latest
```

If you override or provide additional configuration files at runtime, either include them in the image during build or mount them at runtime. The generated CMD expects `app-config.yaml` and `app-config.production.yaml` to be present in the container.

## Quick reference table

| Task                 | Command / Path                                                                        | Notes                                                     |
| -------------------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| Dockerfile location  | `packages/backend/Dockerfile`                                                         | The generated Dockerfile used to build the backend image. |
| Install dependencies | `yarn install --immutable`                                                            | Requires Yarn v3 (Berry).                                 |
| Generate types       | `yarn tsc`                                                                            | Ensures TypeScript artifacts are available.               |
| Build monorepo       | `yarn build`                                                                          | Produces `packages/backend/dist/bundle.tar.gz`.           |
| Build image          | `DOCKER_BUILDKIT=1 docker build -f packages/backend/Dockerfile -t backstage:latest .` | Build context must include `packages/backend/dist`.       |
| Run container        | `docker run --rm -p 7000:7000 backstage:latest`                                       | Adjust ports/config if necessary.                         |

## CI/CD considerations

* Reproduce the local preparation steps in your CI pipeline: install dependencies, run `yarn tsc`, and create the `dist` artifacts.
* Ensure the CI runner enables Docker BuildKit or uses an alternative builder that supports the Dockerfile mount features.
* Push the built image to your container registry and deploy through your preferred orchestrator (Kubernetes, AWS ECS, etc.).
* For multi-stage or automated pipelines, make sure the build context (or artifacts archive) includes `packages/backend/dist` so the Dockerfile COPY steps succeed.

## Links and references

* Backstage documentation: [https://backstage.io/docs](https://backstage.io/docs)
* Docker BuildKit: [https://docs.docker.com/develop/develop-images/build\_enhancements/](https://docs.docker.com/develop/develop-images/build_enhancements/)
* Yarn v3 (Berry): [https://yarnpkg.com/getting-started](https://yarnpkg.com/getting-started)
* Kubernetes: [https://kubernetes.io/docs/](https://kubernetes.io/docs/)
* Amazon ECS: [https://aws.amazon.com/ecs/](https://aws.amazon.com/ecs/)

This sequence packages your Backstage backend into a production-ready Docker image, following recommended practices for reproducible builds and CI/CD.

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/certified-backstage-associate-cba/module/d82fc857-4b5c-42a7-ab46-3772f749a741/lesson/24aeb58f-e979-44e3-802d-917e6b7531a8" />
</CardGroup>
