Migration from Docker Desktop to Colima

2026-10-04

blog-post

A quickstart guide to getting up and running with Colima for your Docker needs.

Goal

This quickstart explains how to replace Docker Desktop with Colima for Docker Compose projects.

Why

Docker Desktop’s licensing changes in August 2021 prompted the search for an alternative.

Colima supports Docker Compose and Buildx through the Docker CLI plugins. Additional features include:

  • Direct access to the Linux VM.
  • More dynamic memory utilization, less memory used when less resources are needed (at least that is my observation).
  • Multiple VM instances through named profiles.

Installation

This guide uses Homebrew, a common installation method on macOS. Other installation options are also available.

Install Homebrew

Install Homebrew if it is not already installed on your system. brew.sh provides the following command. Consider downloading and inspecting the install.sh script before running it.

Shell
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Install Rosetta

To use Rosetta for amd64 containers on Apple Silicon, install it on the host and enable it in Colima’s configuration as shown below.

Shell
softwareupdate --install-rosetta

Install Colima, Docker, Docker Compose, and Docker Buildx

Install Colima and the Docker CLI tools, then configure Compose and Buildx as Docker CLI plugins.

Shell
brew install colima
brew install docker
brew install docker-compose
brew install docker-buildx
Shell
mkdir -p "$HOME/.docker/cli-plugins"
ln -sfn "$(brew --prefix)/opt/docker-compose/bin/docker-compose" "$HOME/.docker/cli-plugins/docker-compose"
ln -sfn "$(brew --prefix)/opt/docker-buildx/bin/docker-buildx" "$HOME/.docker/cli-plugins/docker-buildx"

Verify that the CLI can find both plugins:

Shell
docker compose version
docker buildx version

Shell Autocomplete

If desired, add autocomplete support for Colima.

Zsh

Extend fpath to include a custom directory for completion functions while preserving its existing entries.

Add the following to .zshrc, before any existing call to compinit. If your shell configuration already initializes completion, keep that initialization instead of adding another call.

Shell
fpath=("$HOME/.zsh/functions" "${fpath[@]}")
autoload -Uz compinit
compinit

Run the following commands once to create the directory and generate the Colima completion script:

Shell
mkdir -p "$HOME/.zsh/functions"
colima completion zsh > "$HOME/.zsh/functions/_colima"

Start a new shell to load the completions.

Other Shells

Bash and Fish are also supported.

Configuration

Configure an existing profile with colima start --edit, or edit its configuration file directly. With the default configuration directory, the default profile uses ~/.colima/default/colima.yaml, and named profiles use ~/.colima/<profile-name>/colima.yaml.

My preference is updating the colima template their the CLI to launch an editor. Validation is done on save, and invalid changes are rejected. So it is best to make small, incremental changes.

Shell
colima template

The template is stored at ~/.colima/_templates/default.yaml. Changes to the template apply to new profiles; they do not update existing profiles.

CPU

Choose a CPU allocation that is equal or less to the number of cores on your machine. Personally, I match the number of cores on my machine.

The following example allocates 10 cores; adjust it to suit your hardware and workload.

YAML
cpu: 10

Disk

The default disk size for container data is 100 GiB. Colima can increase an existing disk on startup, but it cannot shrink it in place.

Starting with Colima v0.9.0, container data is stored on a separate disk and preserved across ordinary VM deletion and recreation. Pulled images and other container data are restored when the profile starts again. colima delete --data also deletes that data disk. Reducing its size requires recreating the data disk and backing up any data that needs to be retained.

YAML
disk: 100

Memory

Increase the default 2 GiB allocation if your workload needs more memory, while leaving enough physical memory for macOS and other applications.

For heavier workloads, 32 GiB on a 48 or 64 GiB machine, or 16 GiB on a 24 or 32 GiB machine, may be useful starting points. Smaller workloads may need much less. Monitor memory pressure and adjust the allocation as necessary.

Early observations during this migration suggested that Colima used less host memory than Docker Desktop under lighter workloads. Actual memory use depends on the workload, VM configuration, and software versions; this observation does not establish a general advantage or justify allocating nearly all physical memory to the VM.

YAML
memory: 32

Network

Keep network.address disabled unless you need a directly reachable VM IP address. This setting does not disable the VM’s networking or the usual forwarding of published container ports to localhost.

Some VPN configurations can conflict with the networking used to provide a reachable VM address. Depending on the setup, a DNS conflict on port 53 may prevent the VPN from starting while Colima is running. If this occurs, try disabling network.address and restarting Colima. DNS conflicts can also occur with Docker Desktop, although troubleshooting differs.

YAML
network:
  address: false

The Testcontainers examples below show how to select localhost or the VM’s reachable IP as the host for published container ports. Due to VPN and testcontainers, I have found keeping address false to be easier.

Virtualization

On Apple Silicon, use Apple’s Virtualization framework (vz), especially when running amd64 containers with Rosetta. This backend requires macOS 13 or newer.

YAML
vmType: vz

Enable Rosetta for amd64 containers on Apple Silicon when using vz:

YAML
rosetta: true

Mount Type

Use virtiofs with vz; it is already the default mount type for this backend.

During this migration, some provisioning scripts encountered mount directories before their contents became visible. That timing issue was not observed with virtiofs in the tested setup, but mount readiness should still be considered when writing provisioning scripts.

YAML
mountType: virtiofs

Mounts

Additional mounts may not be necessary, but the Linux VM does not automatically inherit certificates trusted by the macOS Keychain. If a private registry uses a certificate signed by an internal CA, or a self-signed certificate, add the appropriate trust certificate to the VM.

  1. If you add a mount point, the default mount point (one for ~) must be explicitly added.

  2. Create ~/.colima/certs, place the required PEM-encoded .crt certificates there, and add a read-only mount:

YAML
mounts:
  - location: ~/
    writable: true
  - location: ~/.colima/certs
    mountPoint: /certs
    writable: false

Do not use ~ in YAML by itself, as that is treated as null. Either quote as in "~" or add a slash like above, ~/.

  1. Install the certificates into the Linux VM’s trust store during provisioning:
YAML
provision:
  - mode: system
    script: |
      if ls /certs/*.crt >/dev/null 2>&1; then
        install -m 644 /certs/*.crt /usr/local/share/ca-certificates/
        update-ca-certificates --verbose > /tmp/update-ca-certificates.log 2>&1
      fi

Provisioning scripts run on startup, so they should be safe to run repeatedly. If certificate files are not yet visible when provisioning runs, add bounded retry logic before installing them. A delay of about two seconds was observed in the tested setup, but timing can vary. The script above skips installation if no .crt files are visible.

Troubleshooting

Make small configuration edits and check for YAML validation errors when saving. If an edit is rejected, correct the syntax and confirm that the intended changes were saved.

To inspect the VM’s startup logs, connect with colima ssh and run journalctl inside the VM.

Testcontainers

Testcontainers needs the location of Colima’s Docker socket. For the default profile in the default configuration directory, add the following to your shell’s configuration:

DOCKER_HOST points to the socket on the macOS host. TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE specifies the socket path inside the VM for containers such as Ryuk.

Shell
export DOCKER_HOST="unix://${HOME}/.colima/default/docker.sock"
export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock

Adjust your URI according to the colima profile name being used. Use colima status to obtain the actual docker.sock location.

If you left network addressing enabled address: true you will also need to set the TESTCONTAINERS_HOST_OVERRIDE. Set the host override according to how your tests reach published container ports.

Shell
export TESTCONTAINERS_HOST_OVERRIDE="$(colima ls -j | jq -r 'select(.name == "default") | .address')"

Run this command after Colima starts. Update the profile name if you use a named profile, and refresh the variable if the VM’s address changes.

If jq is not currently available, install with brew install jq.

Without addressing, localhost is used. So when address: false either unset TESTCONTAINERS_HOST_OVERRIDE or set it to localhost. Personally, I set it localhost for reminder of what is needed.

Shell
export TESTCONTAINERS_HOST_OVERRIDE=localhost

For complete details, check out the testcontainers official documentation .

All Set

You are now ready to use Colima for your Docker and Docker Compose workloads.

On Demand

Start Colima and use the Docker CLI as before:

Shell
colima start

Colima normally activates its Docker context on startup. An existing DOCKER_HOST setting takes precedence over that context, so ensure it points to the intended profile if you have set it.

When you are done, use colima stop. To restart the VM, use colima restart.

As a Service

If Homebrew was used, you can leverage homebrew to also run colima as a service.

Shell
brew services start colima

Use brew services list to check the status of the service.

The start, stop, and restart are the commands to learn, use brew serives --help for details.

Try It Out

My Kafka Streams Dashboards project is redesigned to work with Colima. While continuing to work with Docker Desktop. There really isn’t much to it, provided the docker compose and docker buildx plugins are properly installed. I just updated my gradle build script to handle multiple docker paths.

While just moving to docker would work too, the build is more robust with the above approach.

kotlin
val dockerExe = listOf(
    "/opt/homebrew/bin/docker",
    "/usr/local/bin/docker",
    "docker"
).firstOrNull {
    it == "docker" || file(it).exists()
} ?: throw GradleException("Docker executable not found")