How to Use mise in CI/CD Pipelines: Complete Configuration Guide
mise is a Rust-based CLI that unifies tool version management and task execution, making it ideal for CI/CD pipelines by providing deterministic, cached environments through commands like mise install and mise exec.
mise (formerly rtx) is a fast, declarative tool version manager maintained in the jdx/mise repository. Using mise in CI/CD pipelines ensures that build, test, and deployment environments match your local development setup exactly, eliminating "works on my machine" errors through its hierarchical configuration system and lockfile support.
Core Architecture for CI/CD
The mise source code is organized into specific modules that handle CI/CD requirements efficiently. Understanding these components helps you optimize pipeline performance and reliability.
CLI Entry and Configuration Loading
In src/main.rs, the CLI bootstrap process parses commands and immediately detects CI environments. When the CI, GITHUB_ACTIONS, or GITLAB_CI environment variables are present, mise automatically switches to "trusted" mode, skipping interactive prompts and assuming configuration files are safe.
The configuration loader in src/config/mod.rs reads mise.toml, .tool-versions, and environment files, merging them hierarchically. This guarantees that every CI runner receives the exact same tool set and environment variables regardless of the base image.
Backend System and Toolset Management
The Backend trait defined in src/backend/mod.rs abstracts version sources including Aqua and GitHub releases. In CI pipelines, the Aqua backend acts as a shared cache for version lists and metadata, dramatically reducing API calls and avoiding rate limits.
Tool resolution happens in src/toolset/mod.rs, which handles version resolution, caching installations in $HOME/.local/share/mise, and creating shims. You can either install tools once with mise install or use on-demand execution—both paths leverage the same cache directory.
CI Detection and Trust Model
Mise automatically treats environments with recognized CI variables as trusted. This trust model, documented in the CLI trust system, means:
- Lockfiles containing checksums are trusted without additional verification
- Interactive prompts are never displayed
- Shims are preferred for speed over permanent
PATHmodifications
Setting Up mise in CI Workflows
Installation and Bootstrapping
Bootstrap mise by downloading a pre-built release or including the binary in your container image. The standard installation script works across Linux, macOS, and Windows runners:
curl -fsSL https://mise.run | sh
echo "$HOME/.local/bin" >> $GITHUB_PATH # For GitHub Actions
Alternatively, commit the ./bin/mise binary directly to your repository for air-gapped or security-hardened environments.
Caching Strategies
Cache the tool directory between pipeline runs to avoid re-downloading. The cache key should include your lockfile hash for optimal invalidation:
# GitHub Actions example
- uses: actions/cache@v4
with:
path: ~/.local/share/mise
key: ${{ runner.os }}-mise-${{ hashFiles('mise.lock') }}
For GitLab CI, set MISE_DATA_DIR to a project-relative path to enable built-in caching:
variables:
MISE_DATA_DIR: $CI_PROJECT_DIR/.mise/mise-data
cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- .mise/
Handling Rate Limits and Authentication
Mise automatically reads the GITHUB_TOKEN environment variable (or tokens from github_tokens.toml) to authenticate GitHub API requests. This prevents unauthenticated rate-limit errors when resolving tool versions in CI.
The Aqua registry further reduces API calls by providing a cached source of truth for version metadata, making pipelines faster and more reliable than direct GitHub API queries.
Execution Patterns in CI
Why mise exec Beats Shell Activation
In src/cli/exec.rs, the mise exec command implements the preferred CI execution pattern. Unlike shell activation (which modifies PATH permanently), exec sets up the environment, runs your command, then exits cleanly.
Benefits for CI/CD:
- Non-interactive: Works in containers without login shells
- Performance: No permanent
PATHpollution; shims can be added once and reused - Isolation: Each step gets a clean environment at
src/cli/exec.rsboundaries, preventing state bleed between tasks
Use this pattern for all build, test, and lint steps:
mise exec -- cargo test --verbose
mise exec -- python -m pytest
mise exec -- node build.js
Task Execution with mise run
The task engine in src/task/mod.rs handles user-defined scripts with parallel execution support. Define tasks in mise.toml and trigger them in CI:
[tasks]
test = "cargo test --all"
lint = "cargo clippy -- -D warnings"
Run them sequentially or in parallel:
mise run test
mise run lint
Complete CI Configuration Examples
GitHub Actions
This workflow installs mise, caches tools using the lockfile, and runs tests through mise exec:
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install mise
run: |
curl -fsSL https://mise.run | sh
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Cache mise tools
uses: actions/cache@v4
with:
path: ${{ runner.home }}/.local/share/mise
key: ${{ runner.os }}-mise-${{ hashFiles('mise.lock') }}
- name: Install project tools
run: mise install
- name: Run tests
run: mise exec -- cargo test --verbose
GitLab CI
For GitLab, configure the data directory to live within the project path for automatic caching:
stages:
- test
variables:
MISE_DATA_DIR: $CI_PROJECT_DIR/.mise/mise-data
test:
image: rust:latest
stage: test
script:
- curl -fsSL https://mise.run | sh
- export PATH=$HOME/.local/bin:$PATH
- mise install
- mise exec -- cargo test --all
cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- .mise/
Docker Integration
Build images that contain mise and a pre-populated tool cache for the fastest CI starts:
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y curl
RUN curl -fsSL https://mise.run | sh && \
echo "$HOME/.local/bin" >> /etc/profile.d/mise.sh
WORKDIR /src
COPY mise.toml mise.lock ./
RUN mise install # Uses lockfile, caches in /root/.local/share/mise
COPY . .
RUN mise exec -- cargo build --release
Lockfiles and Reproducibility
The mise.lock file stores exact versions and checksums for every tool. In CI environments, mise trusts the lockfile and skips verification when checksums and provenance signatures are present, eliminating network calls for already-resolved versions.
According to the mise-lock documentation, this behavior makes mise install idempotent and deterministic—you get the same binaries on every pipeline run without version drift. Commit mise.lock to version control and reference it in your cache keys for optimal CI performance.
Summary
- Bootstrap: Install mise via
curl https://mise.run | shor commit the binary to your repo - Cache: Persist
$HOME/.local/share/miseorMISE_DATA_DIRbetween runs using lockfile-based cache keys - Execute: Use
mise exec -- <command>instead of shell activation for clean, isolated CI steps - Authenticate: Export
GITHUB_TOKENto avoid API rate limits; leverage the Aqua backend for faster metadata resolution - Lock: Commit
mise.lockto ensure reproducible builds and skip redundant verification in CI
Frequently Asked Questions
How does mise detect CI environments?
Mise checks for standard CI environment variables like CI, GITHUB_ACTIONS, and GITLAB_CI during initialization in src/main.rs. When detected, it automatically enables trusted mode, skips interactive prompts, and assumes configuration files are safe according to the trust model documented in src/cli/trust.md.
Should I use mise install or mise exec in pipelines?
Use mise install once at the beginning of your job to populate the cache, then use mise exec -- <command> for individual steps. This pattern, implemented in src/cli/exec.rs, provides isolated environments for each command without permanently modifying the shell's PATH, making it ideal for container-based CI runners.
How do I avoid GitHub API rate limits in CI?
Export a GITHUB_TOKEN environment variable with appropriate scopes—mise automatically uses this for GitHub-hosted tools as documented in docs/dev-tools/github-tokens.md. Additionally, the Aqua backend (src/backend/mod.rs) caches version metadata, significantly reducing direct GitHub API calls compared to other version managers.
Can I use mise with Docker-based CI runners?
Yes. You can either install mise inside the container at runtime or bake it into your Docker image along with a pre-populated tool cache. The latter approach, using mise install during the image build, eliminates download time from your pipeline execution and ensures consistent tooling across all environments.
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 →