Skip to content

Development Environment Automation using Mise

In the past I've been a faithful user of make for automating development and CI/CD workflows, however I've been hearing a lot of good things about Mise recently so I finally decided to give it a try.

The main rationale of using Mise is that it not only provides basic tasks automation, but also provides a suckless approach to managing multiple versions of tools and dependencies, and you don't need to run any activation commands to switch between projects, as it have the magic "direnv" feature built-in.

In terms of the ecosystem at https://mise.jdx.dev/registry.html it seems to be providing majority of the dev tools I use on a daily basis. For things that do not exist in the registry, I can always use the builtin package managers such as apt or brew as the fallback.

Getting Started

I didn't bother installing it via the the Operating system package manager, instead I just yolo'd the one-liner from the Getting Started page:

curl https://mise.run | sh

My ~/.local/bin is already in my PATH so I can run mise right away, otherwise you will need to add it to your PATH manually:

export PATH="$HOME/.local/bin:$PATH"

After that I activated it in my shell:

eval "$(/home/jingkaihe/.local/bin/mise activate bash)"

Then to enable command auto-completion, I installed the usage package via mise:

mise use -g usage # typically it's not needed for majority of the auto-completion addons, but mise for some reasons are special

And then added the following to my ~/.bashrc:

eval "$(mise completion bash --include-bash-completion-lib)"

Project Renovation

The first project that I'm targetting on is kodelet, which is an autonomous AI agent that is capable of running as a detached process. I simply schedule it away to renovate the repo for itself. The end result looks like this https://github.com/jingkaihe/kodelet/pull/142/files

The kodelet agent pretty much ruthlessly churned through the repo and replaced the Makefile with mise equivalents, updated all the documentations and CI configs one-shot. I used the claude-sonnet-4 model as the model, it clearly has mise in its training dataset as it was able to reason about the tool and its usage without any additional context. - Being LLM friendly is always a big plus when it comes to tool adoption!

Docker Integration

One interesting aspect of the migration was updating the Docker configurations for mise compatibility. The mise Docker cookbook provides excellent guidance on this front.

In the kodelet project's end-to-end testing Dockerfile, the changes were substantial - replacing manual tool installation with mise-managed dependencies:

FROM debian:12-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/*

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
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

This approach eliminates the need to manually manage Go versions, Node.js installations, and other development dependencies in Docker images. The mise configuration becomes the single source of truth for all environments.

GitHub Actions

When using Mise in GitHub Actions, you may encounter rate limiting issues since Mise downloads packages from GitHub's artifact system by default. Running parallel jobs that continuously download packages can trigger GitHub's API rate limits, causing pipeline failures. The typical error message looks like this:

golangci-lint@latest:
   0: failed to install aqua:golangci/golangci-lint@2.4.0
   1: HTTP status client error (403 rate limit exceeded) for url (https://api.github.com/repos/golangci/golangci-lint/releases/tags/2.4.0)
   2: HTTP status client error (403 rate limit exceeded) for url (https://api.github.com/repos/golangci/golangci-lint/releases/tags/v2.4.0)

The solution is straightforward - authenticate your requests using the built-in GITHUB_TOKEN. This token is automatically provided by GitHub Actions with generous rate limits for authenticated requests:

      - name: Setup mise
        uses: jdx/mise-action@v2
        with:
          install: true
          cache: true
          experimental: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Note that I am using mise-action as it automated a lot of mundane setup tasks.

Use GitHub release assets

One of Mise's most powerful features is its ability to install tools directly from GitHub release assets. This is particularly valuable for projects that distribute pre-compiled binaries through GitHub releases, eliminating the need to build from source or rely on package managers or bespoken installation scripts.

For projects like kodelet, which provides cross-compiled binaries for multiple platforms as release assets, this feature enables seamless tool installation across different environments without worrying about build dependencies or compilation complexity.

The installation process is straightforward:

# this is currently an experimental feature
mise settings experimental=true

$ mise use -g github:jingkaihe/kodelet
mise ~/.config/mise/config.toml tools: github:jingkaihe/kodelet@0.0.87.alpha

$ which kodelet
/home/jingkaihe/.local/share/mise/installs/github-jingkaihe-kodelet/0.0.87.alpha/kodelet

This approach works exceptionally well for internal tools, custom utilities, or any project that follows the GitHub releases pattern for distributing binaries. The integration feels native and maintains consistency with other mise-managed tools.

Note that this is currently an experimental feature. If you pay close attention to its source code, it appears that by default it relies on some kind of "convention over configuration" file naming convention to detect platform and architecture of the binary tarball, therefore at this stage you should use it at your own risk.

Final Thoughts

I've been using mise for only 2 days but with the simplicity it brings it is easily one of the tools with the most insane ROI that I've ever used this year. Also big shout out to the UX design of the CLI, it is very intuitive, easy to use and LLM friendly.

Also with the assistance from the coding agent, in combination with RTFM (you cannot escape reading the docs), picking up new tools becomes a breeze. The mise documentation is comprehensive and the tool itself provides helpful error messages and guidance when things don't work as expected.