Release Docker Images
Docker support in Nx Release is currently experimental and only available in the next
/beta version. It may undergo breaking changes without following semantic versioning.
This guide walks you through setting up Nx Release to version and publish Docker images from your monorepo using calendar-based versioning.
Prerequisites
Before starting, ensure you have:
- Docker installed and running locally
- Run
docker login
to authenticate with your Docker registry (e.g.,docker login docker.io
for Docker Hub) - Make sure that you are on the
next
/beta version of Nx and Nx plugins (e.g.npx create-nx-workspace@next
for new workspaces)
Install Nx Docker Plugin
❯
nx add @nx/docker@next
This command adds the @nx/docker
plugin to your nx.json
so that projects with a Dockerfile
is automatically configured with Docker targets (e.g. docker:build
and docker:run
).
(Optional) Create Basic Node.js Backend
If you don't already have a backend application, create one using @nx/node
:
❯
nx add @nx/node
❯
nx g @nx/node:app apps/api --docker --framework=express
This generates a Node.js application with a Dockerfile like the following:
1FROM docker.io/node:lts-alpine
2
3ENV HOST=0.0.0.0
4ENV PORT=3000
5
6WORKDIR /app
7
8RUN addgroup --system api && \
9adduser --system -G api api
10
11COPY dist app/
12COPY package.json app/
13RUN chown -R api:api .
14
15# You can remove this install step if you build with `--bundle` option.
16# The bundled output will include external dependencies.
17RUN npm --prefix api --omit=dev -f install
18
19CMD [ "node", "app" ]
20
You should be able to run the following commands to compile the application and create a Docker image:
❯
nx build api
❯
nx docker:build api
Set Up a New Release Group
Configure Docker applications in a separate release group called apps
so it does not conflict with any existing release projects.
1{
2 "release": {
3 "releaseTagPattern": "release/{projectName}/{version}",
4 "groups": {
5 "apps": {
6 "projects": ["api"],
7 "projectsRelationship": "independent",
8 "docker": {
9 // This should be true to skip versioning with other tools like NPM or Rust crates.
10 "skipVersionActions": true,
11 // You can also use a custom registry like `ghcr.io` for GitHub Container Registry.
12 // `docker.io` is the default so you could leave this out for Docker Hub.
13 "registryUrl": "docker.io",
14 // The pre-version command is run before versioning, useful for verifying the Docker image.
15 "groupPreVersionCommand": "echo BEFORE VERSIONING"
16 },
17 "changelog": {
18 "projectChangelogs": true
19 }
20 }
21 }
22 }
23}
24
The release.groups.apps.docker.skipVersionActions
option should be set to true
to skip versioning for other tooling such as NPM or Rust crates.
The release.groups.apps.projectsRelationship
is set to independent
and release.groups.apps.changelog
is set to projectChangelogs
so that each application within the group maintains its own release cadence and changelog.
The release.groups.apps.docker.groupPreVersionCommand
is an optional command that runs before the versioning step, allowing you to perform any pre-version checks such as image verification before continuing the release.
Set Up App Repository
Docker images have to be pushed to a repository, and this must be set on each application you want to release. This must be set as release.docker.repositoryName
in the project's project.json
or package.json
file.
For example, from the previous apps/api
Node.js application, you can set the nx.release.docker.repositoryName
in package.json
.
1{
2 "name": "@acme/api",
3 "version": "0.0.1",
4 "nx": {
5 "release": {
6 "docker": {
7 "repositoryName": "acme/api"
8 }
9 }
10 // ...
11 }
12}
13
Or if you don't have a package.json
(e.g. for non-JS projects), set it in project.json
:
1{
2 "name": "api",
3 "root": "apps/api",
4 "projectType": "application",
5 "release": {
6 "docker": {
7 "repositoryName": "acme/api"
8 }
9 }
10 // ...
11}
12
You should replace acme
with your organization or username for the Docker registry that you are logged into.
Your First Docker Release
Dry run your first Docker release with calendar versioning:
❯
nx release --dockerVersionScheme=production --first-release --dry-run
When you are ready, run the release command again without --dry-run
:
❯
nx release --dockerVersionScheme=production --first-release
When prompted to publish the image, choose yes
, or you can pass the --yes
flag to skip the prompt.
This will:
- Build your Docker images
- Tag them with a calendar version (e.g.,
2501.01.a1b2c3d
) - Update the app's changelog (e.g.
apps/api/CHANGELOG.md
) - Update git tags (you can check with
git --no-pager tag --sort=-version:refname | head -5
) - Push the image to the configured Docker registry (e.g.,
docker.io/acme/api:2501.01.a1b2c3d
)
Understanding Calendar Versioning
Calendar versions follow the pattern YYMM.DD.SHA
:
YYMM
: Year and monthDD
: Day of the monthSHA
: Short commit hash
Note: The timezone is UTC to ensure consistency across different environments.
Future Releases
After the first release, you can run nx release
without the --first-release
flag. If you do not specify --dockerVersionScheme
, then you will be prompted to choose one:
production
- for regular releases from themain
or stable branchhotfix
- for bug fixes from a hotfix branch
These are the default schemes that come with Nx Release. These schemes support workflows where you have a stable branch that developers continuously integrate with, and a hotfix branch reserved for urgent production fixes.
Customizing Version Schemes
You can customize Docker version schemes in your nx.json
to match your deployment workflow. The version patterns support several interpolation tokens:
1{
2 "release": {
3 "dockerVersionScheme": {
4 "production": "{currentDate|YYMM.DD}.{shortCommitSha}",
5 "staging": "{currentDate|YYMM.DD}-staging.{shortCommitSha}"
6 }
7 }
8}
9
The above configuration swaps hotfix
scheme for staging
. You can customize this list to fit your needs, and you can also change the patterns for each scheme.
See the docker.versionScheme
documentation for more details on how to customize the tag pattern.