Running any Mendix™ app in Docker (7–11) without bloating your disk
If you run Mendix™ apps in Docker, you have probably met this: the official
cf-mendix-buildpack image bakes the application model into the image.
That is exactly what you want for an immutable production artifact, but heavier than you need in an
iterative dev/test loop.
We open-sourced the recipes we use internally for that dev loop: github.com/ontologylabs/mendix-runtime-crates (Apache-2.0). They run any Mendix app, versions 7 through 11, without baking the model into the image, and they ship no Mendix binaries.
The dev-loop cost: a new image (and a dangling one) every reload
Because the model is baked in, every model change means a fresh docker build, and the
previous image becomes a dangling layer: ~785 MB each (measured on the
11.6.4 buildpack image). Reload a few dozen times across a working day and you have quietly burned tens of
GB. You end up running docker image prune as a reflex.
The inversion: bake the runtime once, bind-mount the model
The fix is to separate what changes from what does not:
| cf-buildpack image | Runtime crate | |
|---|---|---|
| Mendix™ runtime + JRE | baked | baked (once per version) |
| Application model | baked | bind-mounted |
| Reload | docker build --no-cache | docker compose restart |
| Disk per reload | ~785 MB dangling | 0 |
| Images per version | many (one per commit) | 1 |
Same Mendix version → same image. Ten apps on 11.6.4 → one image, ten bind-mounts.
No binaries: pull the runtime from the CDN at build time
The recipes ship no Mendix™ runtime files. The Dockerfile curls the
runtime from the Mendix CDN at build time, on your machine:
ARG MENDIX_VERSION=11.6.4 ARG RUNTIME_CDN_BASE=https://cdn.mendix.com/runtime RUN curl -fsSL "${RUNTIME_CDN_BASE}/mendix-${MENDIX_VERSION}.tar.gz" ...
So the scaffolding stays clean Apache-2.0 (no redistribution of Mendix IP), and the runtime you
bake is the one you are licensed for. The repo even has a CI guard that fails if anyone commits a
*.tar.gz / *.mda / *.jar or an oversized file. A runtime
binary cannot be merged.
Try it
Build a crate image, then bring it up with Postgres next to it. Step 1 is a one-time
docker build that pulls the runtime from the CDN (a couple of minutes); after that,
reloading a model change is just docker compose restart.
1. Build the runtime image (once per version)
# clone, then build the Mendix 11 crate git clone https://github.com/ontologylabs/mendix-runtime-crates.git cd mendix-runtime-crates/crates/mendix-11 docker build --platform linux/amd64 \ --build-arg MENDIX_VERSION=11.6.4 \ -t ontologylabs/mendix-runtime:11.6.4 .
2. Drop in your unzipped MDA and bring it up
# place an unzipped MDA where the runtime can read it unzip /path/to/your.mda -d ./mda/ # docker-compose.yml — runtime + Postgres on one network services: postgres: image: postgres:14-alpine environment: POSTGRES_USER: mendix POSTGRES_PASSWORD: mendix POSTGRES_DB: mendix healthcheck: test: ["CMD-SHELL", "pg_isready -U mendix"] interval: 5s timeout: 3s retries: 10 mendix-runtime: image: ontologylabs/mendix-runtime:11.6.4 depends_on: postgres: condition: service_healthy ports: - "8080:8080" - "8090:8090" environment: DATABASE_ENDPOINT: "postgres://mendix:mendix@postgres:5432/mendix" ADMIN_PASSWORD: "a-strong-password" DEVELOPMENT_MODE: "true" volumes: - ./mda:/opt/mendix/app - mendix-data:/opt/mendix/data volumes: mendix-data:
docker compose up
# then: curl -fsS http://localhost:8080/
The contract. The runtime reads DATABASE_ENDPOINT (parsed for host,
port, user, password and database), requires a strong ADMIN_PASSWORD, and bind-mounts
the unzipped MDA at /opt/mendix/app. DEVELOPMENT_MODE=true relaxes the
MX 11 project-security gate for local runs. To reload a model change: replace
./mda and run docker compose restart mendix-runtime. No rebuild,
no dangling layer.
Which versions
Crates exist for Mendix™ 7 through 11 (the runtimelauncher.jar +
m2ee boot path is broadly the same across them; the per-version differences, mostly how
model constants are supplied, are handled in each crate’s start.sh). Each
crate’s versions.yaml lists the verified patch versions. Need a version or patch we
don’t cover yet?
open a “Request a Mendix version” issue,
or PR it (build + smoke-test + a versions.yaml row).
Why we built it
We are building mxto, the AI delivery engine for the Mendix™ platform, which reads, authors and ships Mendix apps headless. Clean, reproducible local runtimes are table stakes for that, so these recipes already existed; open-sourcing them was easy. If they save you some disk, a star helps other Mendix developers find them.