Skip to content

Mendix Runtime Crates

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.

no-mendix-binaries License: Apache 2.0 Mendix 7–11

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.

What this is

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 problem it solves

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.

Supported versions

Runtime crates — run an app

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

Build crates — compile an .mpr → .mda

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.

Container engine (no Docker Desktop needed)

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.sh

It 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.

Quick start

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.4

The 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.

How distribution works (and the Mendix IP line)

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.gz during docker 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.

Repository layout

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/ }

Contributing a new version

Freshness is the point of this library. To add a Mendix version:

  1. Add the version to the relevant crate's versions.yaml.
  2. Build it and run the crate's tests/smoke-test.sh against a known-good MDA.
  3. Open a PR with the smoke result noted. The no-mendix-binaries guard must pass.

New majors are welcome as new crates/mendix-<N>/ directories following the same shape.

License

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.

About

Model-agnostic, version-pinned Docker recipes for running any Mendix app (7-11). Recipe-only: no binaries committed; the runtime is pulled from the Mendix CDN at build time. Apache-2.0.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages