Skip to content

Releasing & Building Images

This page is for contributors who need to build Lombok’s release container images locally, or who want to understand how official images get published. It does not cover running or deploying a Lombok instance — for that, see the Self-Hosting pages. For setting up a local development environment, see the Development pages.

It is easy to conflate these, so keep them distinct:

ActivityWhere it happensWhat it produces
Local image buildingYour machine, via ./dx release …A Docker image tagged into your local Docker daemon
CI publishingGitHub Actions, on a version tagMulti-arch images pushed to ghcr.io/lombokapp/…
Deployment / runtimeA server running a published or locally built imageA running Lombok instance

This page covers the first two. The dev container you use for day-to-day work (./dx up) is a different image entirely — it is the dev target of the same Dockerfile and is not a release artifact.

Lombok ships in two flavors, both built from docker/app.Dockerfile:

  • Separate-DB (release target) — the application only. It expects an external PostgreSQL database. Published as ghcr.io/lombokapp/lombok.
  • Standalone (standalone-release target) — the application with PostgreSQL embedded in the image (EMBEDDED_POSTGRES=true). Published as ghcr.io/lombokapp/lombok-standalone.

The standalone target builds on top of the separate-DB target, adding the Postgres packages and an initialized data directory.

The supported entry point is the ./dx CLI:

Terminal window
./dx release standalone <version>
./dx release separate-db <version>

The <version> argument is required. It is used verbatim as:

  1. the build ID baked into the image, and
  2. the tag suffix applied to the resulting local image.

The exact format is up to you — the tooling accepts whatever string you pass. The dx help text shows a semver-style example, while the underlying build scripts also show timestamp-style examples.

Under the hood, ./dx release runs the scripts in deploy/:

  • deploy/build-standalone.sh
  • deploy/build-separate-db.sh

Each runs docker buildx build against the corresponding Dockerfile target.

For a given <version>, the build produces per-architecture tags in your local Docker daemon. For example, ./dx release standalone 1.2.1 yields tags like:

  • lombok-standalone:1.2.1-amd64
  • lombok-standalone:latest-amd64
  • lombok-standalone:1.2.1-arm64
  • lombok-standalone:latest-arm64

The separate-DB build uses the image name lombok instead of lombok-standalone.

Local builds produce architecture-suffixed tags and use --load to load each platform into your local daemon one at a time. They do not assemble a single multi-arch manifest — that only happens in CI.

By default both linux/amd64 and linux/arm64 are built sequentially. Building a platform that does not match your host requires emulation and can be slow. To build only one architecture, use the helper scripts from package.json:

Terminal window
bun run build:standalone arm64
bun run build:separate-db amd64

These helpers auto-generate a build ID in the form <UTC timestamp>-<git short hash> and forward the platform through to the build script. Accepted platform values include amd64, arm64, linux/amd64, and linux/arm64.

[!NOTE] If you call the deploy/build-*.sh scripts directly, the signature is build-<flavor>.sh <build-id> [platform]. Prefer ./dx release or the bun run build:* scripts over invoking them by hand.

Local builds run with --no-cache, so every local release build is a clean build from scratch. This is intentional for reproducibility but makes local release builds slower than incremental dev loops.

Every release image has a build ID baked in at build time via the LOMBOK_BUILD_ID build argument:

  • the UI bundles it as a static /build-id asset
  • the API exposes it at /api/v1/public/build-id

This lets you confirm exactly which build a running instance came from. When you run ./dx release <flavor> <version>, the <version> you pass becomes this build ID.

[!NOTE] Do not confuse this with the dev build ID. During development, ./dx computes a separate per-invocation build ID for the dev container. That value is only for local development and is not used for release images.

Official images are not published from a contributor’s machine. Publishing is handled by .github/workflows/publish.yml, which:

  • triggers on pushing a tag matching v*.*.*
  • builds both flavors for linux/amd64 and linux/arm64 as a multi-arch manifest using docker/build-push-action
  • pushes to GitHub Container Registry:
    • ghcr.io/lombokapp/lombok:<tag> and :latest
    • ghcr.io/lombokapp/lombok-standalone:<tag> and :latest
  • uses the GitHub Actions cache (type=gha) to speed up builds

So the normal release flow is: merge the code, create a version tag, and let CI publish the images.

[!NOTE] Unlike local builds, CI publishes a single tag per flavor that resolves to the correct architecture automatically. There are no -amd64 or -arm64 suffixes on published tags.

You usually do not need to deploy a locally built image, but it can be useful for testing a release image end-to-end before tagging. The repo includes demo compose files that illustrate both patterns:

  • docker-compose.standalone.demo.yml runs lombok-standalone:latest with pull_policy: never, so it uses a locally built image if you tag it that way.
  • docker-compose.demo.yml runs ghcr.io/lombokapp/lombok:latest alongside a separate Postgres container.

Because local builds produce arch-suffixed tags, you may need to retag or adjust compose configuration so the image name matches what the compose file expects.

For runtime configuration such as environment variables, ports, persistent storage, and production deployment shape, use the Self-Hosting docs rather than relying on the demo compose files alone.

Terminal window
# Build standalone (embedded Postgres), both arches, explicit version
./dx release standalone 1.2.1-beta-rc3
# Build separate-DB (external Postgres), both arches, explicit version
./dx release separate-db 1.2.1-beta-rc3
# Build one architecture with an auto-generated build ID
bun run build:standalone arm64
bun run build:separate-db amd64
# Publishing is CI-driven from version tags
# (exact git push flow depends on your maintainer workflow)