From mise-toolkit
The canonical patterns for running mise inside Docker — multi-stage builder/runtime split, BuildKit cache mounts for ~/.local/share/mise/installs, when mise belongs in the runtime stage, and the non-root user pattern. Use when writing a Dockerfile that installs mise or copies mise-managed tools into a container.
npx claudepluginhub ray-manaloto/claude-code-marketplace --plugin mise-toolkitThis skill uses the workspace's default tool permissions.
There's a right way and five wrong ways to put mise in a Dockerfile. This skill covers the right way.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Guides code writing, review, and refactoring with Karpathy-inspired rules to avoid overcomplication, ensure simplicity, surgical changes, and verifiable success criteria.
Share bugs, ideas, or general feedback.
There's a right way and five wrong ways to put mise in a Dockerfile. This skill covers the right way.
mise belongs in the builder stage, not the runtime stage. You install mise, use it to install tools, use those tools to build your app, and then copy the built artifacts into a clean runtime image. The runtime image almost never needs mise itself.
The exception: if the runtime's entrypoint is a mise-managed interpreter (e.g. python app.py and python itself is mise-installed), you need either mise in the runtime stage or (better) a COPY --from=builder of the specific interpreter binary plus its shared libs. The latter is cleaner but fiddlier.
# syntax=docker/dockerfile:1.7
ARG DEBIAN_VERSION=12-slim
# ────────────────────────────────────────────────────────────
# builder stage: install mise + tools, build the app
# ────────────────────────────────────────────────────────────
FROM debian:${DEBIAN_VERSION} AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
curl git ca-certificates build-essential \
&& rm -rf /var/lib/apt/lists/*
# Install mise. Prefer the bootstrap script if ./bin/mise exists (see mise-docker-bootstrap).
ENV MISE_INSTALL_PATH=/usr/local/bin/mise
RUN curl https://mise.run | sh
ENV MISE_TRUSTED_CONFIG_PATHS=/workspace
WORKDIR /workspace
# Copy mise config first for better layer caching.
COPY mise.toml mise.lock ./
# BuildKit cache mount — tools survive across builds, dramatically speeding up rebuilds.
RUN --mount=type=cache,target=/root/.local/share/mise/installs \
mise trust && mise install
# Now the rest of the source.
COPY . .
# Use mise-managed tools via `mise exec` (the shims dir would also work).
RUN mise exec -- <your build command>
# ────────────────────────────────────────────────────────────
# runtime stage: clean base, copy just the artifacts
# ────────────────────────────────────────────────────────────
FROM debian:${DEBIAN_VERSION} AS runtime
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& useradd -m -u 1000 dev
USER dev
WORKDIR /home/dev/app
COPY --from=builder --chown=dev:dev /workspace/target/release/myapp ./
CMD ["./myapp"]
# syntax=docker/dockerfile:1.7 — enables BuildKit features like cache mounts. Without this line, the --mount=type=cache line is a syntax error.~/.local/share/mise/installs — the single biggest build-speed win. Without it, every tool re-downloads and re-installs on every build. With it, incremental builds skip the install entirely.COPY mise.toml mise.lock ./ before the source — layer caching. The tools layer only invalidates when the mise config changes, not when source changes.mise trust && mise install — inside containers, there's no TTY to confirm trust interactively. The MISE_TRUSTED_CONFIG_PATHS=/workspace env var plus the explicit mise trust makes it non-interactive.mise exec -- vs adding shims to PATH — both work in the builder stage. mise exec is more explicit; shims are more convenient if you have many build commands.Only if all three are true:
python, node, ruby, etc.).If those apply, add to runtime:
COPY --from=builder /usr/local/bin/mise /usr/local/bin/mise
COPY --from=builder /root/.local/share/mise /home/dev/.local/share/mise
ENV PATH="/home/dev/.local/share/mise/shims:${PATH}"
But first, try COPY --from=builder /root/.local/share/mise/installs/python/3.12 /usr/local/python and ENV PATH="/usr/local/python/bin:${PATH}" — it's smaller and simpler.
RUN curl ... | sh && mise install without pinning the mise version. Use the bootstrap pattern (mise-docker-bootstrap) for reproducibility.COPY . . before COPY mise.toml — destroys layer caching for the tools install.mise-docker-multistage — deeper dive on the builder/runtime split.mise-docker-base-images — picking the right base (debian vs ubuntu vs alpine vs cuda).mise-docker-bootstrap — the mise generate bootstrap pattern for pinned mise.mise-devcontainer-patterns — when you want a devcontainer on top of this./mise-dockerfile — generates a starting Dockerfile from this pattern.