Model-agnostic, app-agnostic, version-pinned Docker recipes for running and building any Mendix application — Mendix 7 through 11 — without baking the model into the image. Bind-mount your unzipped MDA, set a few env vars, get a working Mendix runtime; or bind-mount a project and compile it to an
.mda, with no Studio Pro on the host.
TL;DR — git clone → cd crates/mendix-11 → docker build (the Mendix runtime
is pulled from the Mendix CDN, not committed) → docker run with your unzipped MDA
bind-mounted. One image per Mendix version, reused across every app at that version,
zero dangling layers. Jump to Quick start ↓
Full write-up: Running Mendix apps headless: the runtime-crates pattern, on mxto.ai.
If you searched for run a Mendix app in Docker, dockerize a Mendix app, Mendix runtime Docker image, Mendix without Studio Pro, self-hosted Mendix container, or Mendix 10 LTS Docker image — this is that.
A set of recipes — Dockerfile, start.sh / build.sh, and supporting
scaffolding — that build a clean, reusable Docker image for each Mendix major
version, in two flavours: a runtime crate (crates/mendix-<N>/) that runs an
app, and a build crate (crates/mendix-<N>/build/) that compiles a project to
an .mda and runs mx check. They contain no Mendix binaries: the Mendix
runtime/toolchain tarball is downloaded from the official Mendix CDN
(cdn.mendix.com) at build time, on your machine. You bring the licensed
runtime; we bring the build recipe.
The official cf-mendix-buildpack Docker pattern bakes the application model
directly into the image. Every model change spawns a new image and orphans the
previous one — typically ~785 MB of dangling layers per reload. An iterative
dev/test loop that reloads many times a day consumes tens of GB of disk in a
single working session.
These crates invert the pattern:
| CF-buildpack image | These crates | |
|---|---|---|
| Mendix runtime files | baked | baked (from CDN at build) |
| JRE | baked | baked |
| Application model | baked | bind-mounted |
| Reload mechanism | docker build --no-cache |
docker compose restart |
| Disk cost per reload | ~785 MB (dangling) | 0 |
| Images per Mendix version | many (one per app commit) | 1 |
| Reusable across apps | no | yes |
Same Mendix version → same image. Multiple apps at the same version → one image, multiple bind-mounts.
| Crate | Verified Mendix version | JRE | Base image | Status |
|---|---|---|---|---|
crates/mendix-11 |
11.6.4 |
Java 21 | eclipse-temurin:21-jre-jammy |
verified |
crates/mendix-10 |
10.24.13.86719 (LTS) |
Java 21 | eclipse-temurin:21-jre-jammy |
verified |
crates/mendix-9 |
9.24.20.33307 |
Java 11 | eclipse-temurin:11-jre-jammy |
verified |
crates/mendix-8 |
8.18.35.97 (final LTS) |
Java 11 | eclipse-temurin:11-jre-jammy |
recipe (CDN 200) |
crates/mendix-7 |
7.23.8.58888 |
Java 8 | eclipse-temurin:8-jre-jammy |
verified |
Each version also ships a build crate under crates/mendix-<N>/build/: a
version-pinned mxbuild (+ mx, on Mendix 9 and later) toolchain image that
compiles a project, with nothing on the host but Docker (no Studio Pro). The
toolchain is pulled from the same CDN as mxbuild-<version>.tar.gz. See
Building MDAs in Docker.
⚠ mx check does not exist on every major — the CDN toolchain for Mendix 7 has no
mx binary at all, and Mendix 8's mx has no check verb. check first works at
Mendix 9. See
mx check is not available on every major.
build (the .mpr → .mda compile) works identically on every major below.
| Build crate | mxbuild version | JDK | Base image | Status |
|---|---|---|---|---|
crates/mendix-11/build |
11.6.4 |
Java 21 | eclipse-temurin:21-jdk-jammy |
image-verified¹ |
crates/mendix-10/build |
10.24.13.86719 |
Java 21 | eclipse-temurin:21-jdk-jammy |
MDA-verified² (default patch: recipe, CDN 200) |
crates/mendix-9/build |
9.24.20.33307 |
Java 11 | eclipse-temurin:11-jdk-jammy |
MDA-verified⁵ (default patch: recipe, CDN 200) |
crates/mendix-8/build |
8.18.35.97 |
Java 11 | eclipse-temurin:11-jdk-jammy |
MDA-verified⁴ |
crates/mendix-7/build |
7.23.8.58888 |
Java 8 | eclipse-temurin:8-jdk-jammy |
recipe (CDN 200) — first .mda attempt made³, not yet closed |
¹ image-verified = the image builds, the CDN toolchain pull succeeds, and the
binaries + entrypoint resolve and run; a full .mpr → .mda compile against a
licensed project is the remaining smoke gate (per crate provenance.yaml).
² MDA-verified = at a newer patch than the crate's listed default
(10.24.22.113362), this crate compiled a real ~7,000-file production project
end to end (BUILD SUCCEEDED, an 84 MB .mda) over three independent runs —
see crates/mendix-10/build/versions.yaml
for the measured timings and Building MDAs in Docker
for what it costs. The crate's default patch (10.24.13.86719) has not itself
been build-tested — pin the newer patch with --build-arg MENDIX_VERSION=10.24.22.113362
if you want the version that has actually been proven.
³ first .mda attempt made = the image itself is proven (toolchain extracts, binaries
resolve) and a real compile was run against it — but the project available for the attempt
was missing its theme/widgets content locally, so mxbuild refused on missing-content
errors rather than producing an .mda. Named honestly rather than left pending silently;
see each crate's versions.yaml for the exact errors (on Mendix 7: 14 errors resolving to
5 exactly-named missing widgets) and what's needed to close it.
⁴ MDA-verified = a real, full-content project (~2,960 files) compiled end to end
(BUILD SUCCEEDED, a 140 MB / 3,569-entry .mda, 63s wall) — see
crates/mendix-8/build/versions.yaml.
⁵ MDA-verified = at a newer patch than the crate's listed default (9.24.36.73625), this
crate compiled a real full-content project (2,704 files: javasource 1,677 / theme 197 /
widgets 52 / userlib 301) end to end (BUILD SUCCEEDED, a 180 MB / 4,020-entry .mda, 124s
wall) — see crates/mendix-9/build/versions.yaml. The
crate's default patch (9.24.20.33307) has not itself been build-tested against a
full-content project — pin the newer patch with --build-arg MENDIX_VERSION=9.24.36.73625
if you want the version that has actually been proven.
recipe (CDN 200) = authored to the same proven pattern with the CDN source
URL verified reachable, image build pending.
Each crate's versions.yaml lists the exact versions it targets. The runtime
boot path (runtimelauncher.jar + the m2ee admin protocol) and the build
invocation are identical from Mendix 7 through 11. Mendix 8 is out of
standard support but its final LTS patch (8.18.35.97) is still CDN-hosted;
older MX8 patches that aren't are covered by
crates/mendix-8/PORTAL-DOWNLOAD.md.
These recipes use only the plain docker CLI, so any Docker-API-compatible engine works — you do
not need Docker Desktop. If docker info already succeeds, skip ahead to the Quick start.
Otherwise an OS-aware, idempotent bootstrap is included:
./scripts/devops/bootstrap-container-engine.shIt sets up a headless, free engine — macOS / Linux → Colima,
Windows → Podman — installs and starts it, removes Docker Desktop's credsStore
(which otherwise breaks headless image pulls), and verifies docker info, buildx, and compose. See
.claude/skills/container-build/ for engine gotchas.
git clone https://github.com/ontologylabs/mendix-runtime-crates.git
cd mendix-runtime-crates/crates/mendix-11
# Build — the Mendix 11.6.4 runtime is curl'd from the Mendix CDN during this step
docker build \
--platform linux/amd64 \
--build-arg MENDIX_VERSION=11.6.4 \
-t ontologylabs/mendix-runtime:11.6.4 \
-t ontologylabs/mendix-runtime:11 \
.
# Run — bind-mount your unzipped MDA; the model is never baked in
docker run -d --name my-mendix \
-p 8080:8080 -p 8090:8090 \
-v /path/to/unzipped/mda:/opt/mendix/app:ro \
-v my-mendix-data:/opt/mendix/data \
-e DATABASE_ENDPOINT="postgres://mendix:mendix@db:5432/mendix" \
-e ADMIN_PASSWORD="a-strong-password" \
-e DEVELOPMENT_MODE="true" \
ontologylabs/mendix-runtime:11.6.4The image tag (ontologylabs/mendix-runtime:…) is a local tag you choose at
build time — these recipes publish no registry image, so name it whatever suits
your pipeline. See each crate's README.md for the full env-var contract,
bind-mount layout, and a docker compose smoke example.
These recipes are distributed recipe-only:
- What's in this repo — Dockerfiles,
start.sh,versions.yaml,provenance.yaml, tests, and docs. All of it is original scaffolding, licensed Apache-2.0 (see LICENSE). It contains no Mendix code. - What's not in this repo — the Mendix runtime itself. It is fetched from
https://cdn.mendix.com/runtime/mendix-<version>.tar.gzduringdocker build, on your machine. The runtime you download is subject to Mendix's own license (https://www.mendix.com/terms-of-use/). No upstream Mendix code is forked, modified, or redistributed here.
A CI guard (.github/workflows/no-mendix-binaries.yml) enforces this on every
push and pull request: it rejects any commit that introduces a Mendix-binary
file pattern (*.tar.gz, *.mda, *.mpr, *.jar, …) or any file over 256 KB.
A Mendix tarball can never be merged into this repository.
mendix-runtime-crates/
├── README.md
├── LICENSE # Apache-2.0
├── guard.sh # the no-Mendix-binary CI check
├── .github/workflows/no-mendix-binaries.yml # runs guard.sh on push + PR
├── docs/
│ ├── running-mendix-<N>-in-docker.md # per-version run guides
│ └── building-mendix-apps-in-docker.md # compile an .mpr → .mda
└── crates/
├── mendix-7/ { Dockerfile, start.sh, versions.yaml, provenance.yaml, README.md, CHANGELOG.md, tests/ }
│ └── build/ { Dockerfile, build.sh, versions.yaml, provenance.yaml, README.md, CHANGELOG.md, tests/ }
├── mendix-8/ { …runtime… , PORTAL-DOWNLOAD.md, build/ } # final 8.18 LTS; portal fallback for older patches
├── mendix-9/ { …runtime… , build/ }
├── mendix-10/ { …runtime… , build/ }
└── mendix-11/ { …runtime… , build/ }
Freshness is the point of this library. To add a Mendix version:
- Add the version to the relevant crate's
versions.yaml. - Build it and run the crate's
tests/smoke-test.shagainst a known-good MDA. - Open a PR with the smoke result noted. The
no-mendix-binariesguard must pass.
New majors are welcome as new crates/mendix-<N>/ directories following the same
shape.
Apache License 2.0 — see LICENSE. Copyright © 2026 Ontology Labs, Inc.
The Mendix runtime fetched at build time is licensed separately by Mendix.
Maintained by Ontology Labs, the team behind mxto.ai — tooling for working with Mendix applications as first-class, version-controlled, AI-readable artifacts. If cross-version Mendix Docker plumbing is a pain you recognise, the rest of what we build may interest you.