How to Use mise for Docker Development: System Installs and OCI Workflows
Use mise in Docker by installing it via the official installer script, configuring shared directories like MISE_DATA_DIR, and running mise install --system to make tools available globally. For ephemeral workflows, enable the experimental OCI backend to build, run, and push container images directly from your mise.toml configuration without maintaining separate Dockerfiles.
mise is a fast, cross-platform version manager designed to handle toolchains inside Docker containers as seamlessly as on physical hosts. According to the jdx/mise source code, the tool manages shims, install paths, and environment variables within containers through its core CLI entry point at src/main.rs and dedicated OCI modules in src/oci/. This guide demonstrates how to provision reproducible development environments using both traditional Dockerfile-based installations and the experimental OCI commands.
How mise Integrates with Docker Containers
When running inside a container, mise treats the environment as a standard host while respecting Docker-specific constraints around user permissions and filesystem layouts. The implementation spans several key components in the codebase:
src/main.rs– The CLI entry point that parses sub-commands likedocker,oci, andinstall, forwarding execution to the appropriate backends.src/oci/builder.rs– Handles the creation of OCI image layouts frommise.tomlconfigurations, including layer generation and package resolution.src/oci/docker_archive.rs– Streams OCI layouts into Docker via thedocker loadcommand.src/toolset/mod.rs– Manages tool resolution and writes shims to the appropriate install directories, supporting both per-user and system-wide installations.src/config/mod.rs– Expands environment variables likeMISE_DATA_DIRandMISE_SYSTEM_DATA_DIRthat control where tools persist in containerized environments.
Inside a container, mise operates through four primary stages: installation via the official script, configuration of shared directories to avoid conflicts with mounted home folders, system-wide tool installation using the --system flag, and optional OCI workflow execution for temporary runtime environments.
Installing mise in a Dockerfile
The standard approach embeds mise directly into your image during the build process. The official Docker cookbook in the repository recommends setting standardized environment variables before installation to ensure tools are stored in shared locations rather than the container's home directory.
# Based on docs/mise-cookbook/docker.md (lines 7-26)
FROM debian:13-slim
RUN apt-get update && \
apt-get -y --no-install-recommends install \
sudo curl git ca-certificates build-essential && \
rm -rf /var/lib/apt/lists/*
ENV MISE_DATA_DIR="/mise"
ENV MISE_CONFIG_DIR="/mise"
ENV MISE_CACHE_DIR="/mise/cache"
ENV MISE_INSTALL_PATH="/usr/local/bin/mise"
ENV PATH="/mise/shims:$PATH"
RUN curl https://mise.run | sh
Build and run the container to verify the installation:
docker build -t debian-mise .
docker run -it --rm debian-mise
Setting MISE_DATA_DIR to /mise ensures tool installations persist in a shared volume that remains accessible regardless of which user runs commands inside the container.
Managing System-Wide Tools
By default, mise installs tools to the user's home directory, which causes conflicts when containers mount host home folders. Use the --system flag to install tools globally under /usr/local/share/mise/installs, making them available to all users.
# Based on docs/mise-cookbook/docker.md (lines 60-62)
RUN mise install --system node@26 python@3.15
After the container starts, verify system-wide availability:
$ mise ls
node 26.0.0 (system)
python 3.15.0 (system)
The --system flag triggers the logic in src/toolset/mod.rs to write binaries to the system data directory rather than the user-specific path. You can further customize this behavior by setting MISE_SYSTEM_DATA_DIR or MISE_SHARED_INSTALL_DIRS environment variables before running install commands.
Using Experimental OCI Commands
For scenarios requiring ephemeral environments without pre-built images, mise supports experimental OCI commands that build and run containers directly from your mise.toml. Enable these features by setting MISE_EXPERIMENTAL=1.
Building OCI Images from mise.toml
The mise oci build command creates an OCI-compliant image layout from your current configuration, optionally including bootstrap packages defined in [bootstrap.packages]:
MISE_EXPERIMENTAL=1 mise oci build -o ./img
The src/oci/builder.rs module handles layer generation, while src/oci/docker_archive.rs manages the streaming logic that loads the image into Docker's local registry.
Running Temporary Containers
Execute commands in reproducible environments without maintaining a Dockerfile using mise oci run:
# Based on docs/dev-tools/mise-oci.md (lines 108-114)
MISE_EXPERIMENTAL=1 mise oci run -e DEBUG=1 \
--volume "$PWD:/work" -w /work -- npm test
This command performs three steps: building the OCI layout from mise.toml, streaming it to docker load, and executing docker run with the specified volume mounts and working directory. The container is automatically removed after execution completes.
Pushing to Registries
Push custom development images to container registries using the oci push command, which automatically detects credentials from ~/.docker/config.json or ~/.config/containers/auth.json:
# Based on docs/dev-tools/mise-oci.md (lines 219-220)
mise oci build -o ./img
mise oci push --image-dir ./img ghcr.io/me/devenv:v1
Handling libc in Minimal Base Images
When building minimal containers using scratch or distroless bases, mise may fail to detect the correct C library implementation. Explicitly set the libc environment variable in your mise.toml to ensure mise selects compatible binary variants:
# mise.toml (example)
[env]
libc = "glibc"
This configuration ensures that tools dependent on specific libc implementations receive the correct binaries during installation, particularly when the container lacks the filesystem markers mise typically uses for detection.
Summary
- Install mise in Docker by curling the installer script and setting
MISE_DATA_DIRto a shared path like/miseto avoid home-directory conflicts. - Use
--systemwithmise installto write tools to/usr/local/share/mise/installs, making them available globally inside the container. - Enable OCI workflows by setting
MISE_EXPERIMENTAL=1to build temporary images directly frommise.tomlusingmise oci buildandmise oci run. - Explicitly configure
libcinmise.tomlwhen using minimal base images to ensure correct binary selection. - Reference implementation details in
src/oci/builder.rsandsrc/toolset/mod.rsto understand how mise routes commands and manages installations in containerized environments.
Frequently Asked Questions
How do I prevent mise from installing tools to the home directory inside a Docker container?
Set MISE_DATA_DIR to a system path like /mise and add /mise/shims to PATH before installing mise. This configuration, defined in src/config/mod.rs, redirects all tool installations and shims to the shared directory, preventing conflicts when the host's home directory is mounted into the container.
What is the difference between mise install and mise install --system in Docker?
Standard mise install writes tools to $HOME/.local/share/mise/installs, which may be overwritten if you mount your host home directory into the container. The --system flag, handled by the logic in src/toolset/mod.rs, instead writes to /usr/local/share/mise/installs (or the path specified by MISE_SYSTEM_DATA_DIR), making tools available to all container users regardless of home directory mounting.
Do I need to write a Dockerfile to use mise with Docker?
No. While Dockerfile-based installation provides persistent development images, you can use the experimental mise oci run command to execute commands in temporary containers built directly from your mise.toml. This workflow, implemented in src/oci/builder.rs and src/oci/docker_archive.rs, streams the OCI layout to Docker via docker load and executes your command without maintaining a separate Dockerfile.
Why are the mise oci commands marked as experimental?
The OCI commands require MISE_EXPERIMENTAL=1 because they rely on interaction with external container engines (Docker or Podman) through docker load and docker run, as implemented in src/oci/docker_archive.rs. The API and behavior may change as the feature stabilizes, and it requires the host system to have a compatible OCI runtime installed.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →