___  ___  _ __ ___  _ __   __ _ _ __| |_ _ __ ___   ___ _ __ | |_
 / __|/ _ \| '_ ` _ \| '_ \ / _` | '__| __| '_ ` _ \ / _ \ '_ \| __|
| (__| (_) | | | | | | |_) | (_| | |  | |_| | | | | |  __/ | | | |_
 \___|\___/|_| |_| |_| .__/ \__,_|_|   \__|_| |_| |_|\___|_| |_|\__|
                      |_|

Run multiple local services in parallel without port conflicts. Perfect for multi-project development environments.

Spin up multiple versions of PostgreSQL, Redis, and other services simultaneously — each isolated by name and accessible via DNS.

GitHub Download

Key Features

Parallel Service Instances

Run multiple instances of the same service with different versions simultaneously.

No Port Conflicts

Access services via unique DNS names, avoiding port conflicts entirely.

Data Persistence

Data persists between container restarts with automatic volume management.

Quick start

Requires Docker installed and running.

# macOS
brew tap lcmen/extra
brew install compartment

# Linux / Windows (WSL2)
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
URL=https://github.com/lcmen/compartment/releases/latest/download
curl -fsSL $URL/compartment-linux-$ARCH -o ~/.local/bin/compartment
chmod +x ~/.local/bin/compartment

# Verify installation
compartment check

DNS Configuration

DNS Server

Start the built-in DNS server so services are reachable by name:

compartment start devdns

On WSL2, port 53 is owned by systemd-resolved — use a different host port, then restart the resolver so it picks up the running devdns (complete the WSL2 resolver setup below first):

compartment -e DNS_PORT=5353 start devdns sudo systemctl restart systemd-resolved

Resolver

The custom resolver allows you to route all .container requests to your DNS server running inside the devdns container.

macOS (Docker Desktop)

Create /etc/resolver/container:

nameserver 127.0.0.1

Not needed for OrbStack — it handles DNS resolution automatically.

Linux

Configure systemd-resolved to forward *.container queries to devdns:

sudo mkdir -p /etc/systemd/resolved.conf.d sudo tee /etc/systemd/resolved.conf.d/devdns.conf << 'EOF' [Resolve] DNS=127.0.0.1 Domains=~container EOF sudo systemctl restart systemd-resolved

Linux (WSL2)

WSL overwrites /etc/resolv.conf on startup, bypassing systemd-resolved. Fix this first (run once):

# Stop WSL from overwriting resolv.conf echo -e "[network]\ngenerateResolvConf = false" | sudo tee -a /etc/wsl.conf # Append systemd-resolved nameserver to resolv.conf echo 'nameserver 127.0.0.53' | sudo tee -a /etc/resolv.conf # Restart WSL from PowerShell to apply wsl.conf changes wsl.exe --shutdown

All existing DNS continues to work — internet, VPN, and local hostnames resolve through the Windows DNS fallback as before. Fully reversible: remove the [network] block from /etc/wsl.conf and restart WSL to restore automatic DNS management.

Configure systemd-resolved to forward *.container queries to devdns and Windows DNS as fallback:

sudo mkdir -p /etc/systemd/resolved.conf.d sudo tee /etc/systemd/resolved.conf.d/devdns.conf << 'EOF' [Resolve] DNS=127.0.0.1:5353 10.255.255.254 Domains=~container ~. EOF sudo systemctl restart systemd-resolved

Example usage

# Start PostgreSQL 15 for legacy project
compartment -n legacy.db start postgresql 15

# Start PostgreSQL 17 for new project
compartment -n newapp.db start postgresql 17

# Add Redis for caching
compartment -n newapp.cache start redis 8

# Check what's running
compartment status legacy.db
compartment status newapp.db

# Access via DNS (with devdns)
psql -h legacy.db.container -U postgres
psql -h newapp.db.container -U postgres

Services

PostgreSQL — default version: 18

Image: postgres:<version>

VariableDefault
POSTGRES_USERpostgres
POSTGRES_PASSWORDpostgres
POSTGRES_DBpostgres

Redis — default version: 8

Image: redis:<version>

No environment variables.