CodePier CLI
The CodePier CLI is a Kubernetes development environment hot-swap tool. It replaces running pods with local development containers, syncs your code in real-time, forwards ports, and proxies traffic — so you can develop against a live cluster as if it were local.
Managed by the App
The CodePier desktop app installs and updates the CLI automatically. You only need manual installation for headless environments (CI, remote servers) or if you prefer to manage it yourself.
Installation
macOS / Linux
curl -fsSL https://get.codepier.dev | shWindows (PowerShell)
irm https://get.codepier.dev/install.ps1 | iexDownload binaries
Pre-built binaries for every platform:
codepier-darwin-arm64— macOS Apple Siliconcodepier-darwin-x64— macOS Intelcodepier-linux-arm64— Linux ARM64codepier-linux-x64— Linux x64codepier-windows-x64.exe— Windows x64
Verify
codepier --versionConfiguration
Create a codepier.yaml file in the root of your project. This file tells the CLI how to swap your deployment, what to sync, and how to route traffic.
sync
Paths to synchronize between your local machine and the pod. Each entry maps a local path to a container path separated by a colon.
sync:
- "./src:/app/src"
- "./package.json:/app/package.json"image
The development image to use for the swapped pod. Can be a single string or an architecture-specific map.
# Single image
image: "node:20-slim"
# Architecture-specific images
image:
arm64: "myregistry/dev-image:arm64"
amd64: "myregistry/dev-image:amd64"forward
Port forwards from your local machine to the pod. Format: local:remote.
forward:
- "3000:3000"
- "9229:9229" # Node.js debuggernamespaces
Kubernetes namespace(s) to target. A single string skips the interactive prompt. An array lets you limit the choices.
# Single namespace — skips prompt
namespaces: "staging"
# Multiple namespaces — prompts to choose
namespaces:
- "staging"
- "development"workload
Workload name(s) to target. Same behavior as namespaces — a single value skips the prompt. The legacy deployment field is still accepted as an alias.
# Single workload — skips prompt
workload: "api-server"
# Multiple workloads — prompts to choose
workload:
- "api-server"
- "worker"kind
The workload kind to target. Defaults to Deployment. For DaemonSet workloads the swap pod is pinned to a single node — you'll be prompted to pick one, or you can pass --node.
kind: "StatefulSet" # or "Deployment" (default), "DaemonSet"ignore
Gitignore-style patterns to exclude from file sync. Useful for keeping large directories like node_modules or build artifacts out of the sync.
ignore:
- "node_modules"
- ".git"
- "dist"
- "*.log"supplemental
When true, adds a new sidecar container to the pod instead of replacing the existing one. Useful when you need the original container to keep running alongside your dev environment.
supplemental: truecache
Persistent cache volumes that survive pod restarts. Ideal for package manager caches, build caches, or any directory you want to persist between sessions. You can use a plain path or a name:path format to give the cache a descriptive name.
cache:
# Named caches — the name is used as the volume identifier
- npm:~/.npm
- pip:~/.cache/pip
# Plain path caches
- /app/node_modules
- /root/.cacheworkdir
The working directory inside the container. This is where the SSH session starts.
workdir: "/app"containers
Restricts which containers can be targeted for hot-swap. Only the containers listed here will be available for selection. If omitted, all containers in the pod are available.
containers:
- "api"proxy
HTTPS reverse proxy entries. Each entry maps a local hostname to an upstream — either a Kubernetes service (port-forwarded automatically) or, when service is omitted, a port on your local machine. The CLI generates trusted certificates via mkcert and listens on port 443 by default (see proxyPort).
proxy:
# Forward to a Kubernetes service
- hostname: "api.codepier.local"
service: "api-server" # K8s service name
port: 3000
# Omit service — forward to a local port instead
# (e.g. a dev server running on your machine)
- hostname: "app.codepier.local"
port: 5173Hostnames ending in .local are automatically published via mDNS, so they resolve on your machine and across your LAN without editing /etc/hosts. The proxy forwards X-Forwarded-Host, X-Forwarded-Port, and X-Forwarded-Proto headers and supports WebSocket upgrades.
Path-prefix routes
Each entry can declare routes to send specific path prefixes to a different upstream than the host default — useful for mirroring a production ingress locally (e.g. codepier.local/auth → the API service). A prefix matches the exact path and any subpath (/auth matches /auth/github but not /authxyz). First match wins.
proxy:
- hostname: "codepier.local"
port: 3000 # default upstream: local dev server
routes:
- pathPrefix: "/auth"
service: "api-server" # /auth/* goes to the cluster API instead
port: 4000remoteHostname
Overrides the Host header sent upstream. Use it when the local listen name differs from what the cluster ingress or backend expects — e.g. listen on dev.api.codepier.local but forward as api.codepier.local. Available on both top-level entries and path routes.
proxy:
- hostname: "dev.api.codepier.local"
remoteHostname: "api.codepier.local"
service: "api-server"
port: 3000proxyPort
The HTTPS port the proxy listens on. Defaults to 443, which may require sudo — use a high port like 8443 to avoid that. Can also be set per-run with --port.
proxyPort: 8443env
Environment variables to inject into the dev container. You can set explicit values or forward variables from your local shell with from_env: true.
env:
- name: "NODE_ENV"
value: "development"
- name: "DATABASE_URL"
value: "postgresql://localhost:5432/mydb"
# Forward from your local shell
- name: "AWS_ACCESS_KEY_ID"
from_env: true
- name: "AWS_SECRET_ACCESS_KEY"
from_env: trueCommands
codepier up
The core command. Hot-swaps a Kubernetes workload (Deployment, StatefulSet, or DaemonSet) with a local development container. It scales down the original workload, creates a hot-swap pod with your chosen image, starts real-time file sync via Mutagen, and drops you into an SSH session. When you exit, the original workload is restored automatically. DaemonSet swaps are pinned to a single node — pick one interactively or pass --node.
# Interactive — prompts for namespace, workload, and container
codepier up
# Non-interactive — skip all prompts
codepier up --namespace staging --deployment api-server --container api
# DaemonSet swap pinned to a specific node
codepier up --deployment log-agent --node worker-2codepier down
Stops active hot swaps. Lists all hot-swapped deployments and lets you select which ones to restore. Each selected deployment is scaled back up and the hot-swap pod is removed.
codepier downcodepier ssh
Opens an SSH session directly into a running pod. Works with both regular and hot-swapped pods.
# SSH into the default container
codepier ssh
# SSH into a specific container
codepier ssh --container workercodepier tail
Streams pod logs to your terminal in real-time. If the pod is hot-swapped, it will notify you that logs aren't available since the container runs a sleep process.
# Tail the default container
codepier tail
# Tail a specific container
codepier tail --container apicodepier proxy
Starts a local HTTPS reverse proxy based on the proxy entries in your codepier.yaml. On first run it installs a local mkcert CA into your system trust store (you'll be prompted for your password), then generates TLS certificates from it — so browsers trust the proxy without warnings. It port-forwards to each Kubernetes service with automatic reconnection, routes traffic by hostname and path prefix, publishes .local hostnames over mDNS, and supports WebSocket upgrades. A live status display shows each route's connection state.
# Start the proxy (listens on 443 by default)
codepier proxy
# Listen on a non-privileged port instead
codepier proxy --port 8443
# Start proxy and run a command once ready.
# Runs in a shell (pipes, && etc. work) and the mkcert CA is passed
# via NODE_EXTRA_CA_CERTS so child processes trust the proxy.
codepier proxy --exec "pnpm run codegen && pnpm dev"codepier clean
Removes orphaned file sync directories from cluster nodes. Useful for cleaning up after interrupted sessions or stale hot-swaps.
codepier cleancodepier sync-status
Displays the current Mutagen file synchronization status — which sessions are active, their sync state, and any conflicts.
codepier sync-statuscodepier mutagen
Direct passthrough to the Mutagen CLI for advanced debugging. Accepts any Mutagen subcommand. Also supports license activation.
# Run any mutagen command
codepier mutagen sync list
codepier mutagen sync monitor
# Activate a Mutagen license
codepier mutagen license activate <license-key>codepier update
Checks for the latest CLI release and self-updates. Shows version comparison and prompts for confirmation.
codepier updatecodepier uninstall
Completely removes the CLI binary and the ~/.codepier config directory from your machine.
codepier uninstallGlobal Options
These flags can be passed to any command.
| Flag | Description |
|---|---|
| --config <path> | Path to kubeconfig file (default: ~/.kube/codepier) |
| --context <name> | Kubernetes context to use |
| --namespace <name> | Kubernetes namespace (skips interactive prompt) |
| --deployment <name> | Workload name (skips interactive prompt) |
| --container <name> | Container name (skips interactive prompt). If containers is set in your codepier.yaml, must be one of the allowed containers |
| --pod <name> | Pod name to target (skips prompt when multiple match) |
| --node <name> | Node to pin a DaemonSet swap to (skips interactive prompt) |
| --temp-dir | Use emptyDir instead of hostPath for sync volumes |
Examples
Getting Started
The simplest possible config. Swaps a deployment with a dev image, syncs your entire project, and caches npm packages between sessions.
workload: hello-world
namespaces:
- hello-world
image: node:24-slim
workdir: /opt/hello-world
sync:
- ".:/opt/hello-world"
ignore:
- "node_modules"
- ".git"
cache:
- npm:~/.npmNode.js API with Port Forwarding
A more complete setup for developing a Node.js service. Syncs specific source paths, forwards the app port and debugger, and uses named caches.
workload: api-server
namespaces:
- staging
image: node:20-slim
workdir: /app
sync:
- "./src:/app/src"
- "./package.json:/app/package.json"
- "./tsconfig.json:/app/tsconfig.json"
forward:
- "3000:3000"
- "9229:9229"
ignore:
- "node_modules"
- "dist"
- ".git"
- "*.log"
cache:
- npm:~/.npm
env:
- name: "NODE_ENV"
value: "development"Multi-Service with HTTPS Proxy
Route local HTTPS traffic to Kubernetes services and a local dev server, mirroring the production ingress with path routes. Run codepier proxy to start the reverse proxy, then access each service via its hostname — the .local names resolve automatically via mDNS.
namespaces: "staging"
workload: "api-server"
image: "node:20-slim"
workdir: "/app"
sync:
- ".:/app"
forward:
- "3000:3000"
ignore:
- "node_modules"
- ".git"
cache:
- "/app/node_modules"
proxyPort: 8443
proxy:
# Local dev server, with /auth handled by the cluster API
- hostname: "app.codepier.local"
port: 5173
routes:
- pathPrefix: "/auth"
service: "api-server"
port: 4000
- hostname: "api.codepier.local"
service: "api-server"
port: 3000
- hostname: "auth.codepier.local"
service: "auth-service"
port: 4000
env:
- name: "NODE_ENV"
value: "development"
- name: "API_URL"
value: "https://api.codepier.local:8443"Multi-Architecture with Supplemental Container
Use architecture-specific images and add a sidecar container instead of replacing the original. This is useful when you need the original container's processes to keep running alongside your dev environment.
namespaces:
- "staging"
- "production"
workload:
- "worker"
- "scheduler"
kind: "Deployment"
supplemental: true
image:
arm64: "ghcr.io/myorg/dev-image:arm64"
amd64: "ghcr.io/myorg/dev-image:amd64"
workdir: "/app"
sync:
- "./src:/app/src"
- "./config:/app/config"
forward:
- "8080:8080"
ignore:
- "node_modules"
- ".git"
- "dist"
- "coverage"
cache:
- "/app/node_modules"
- "/root/.cache"
env:
- name: "NODE_ENV"
value: "development"
- name: "AWS_ACCESS_KEY_ID"
from_env: true
- name: "AWS_SECRET_ACCESS_KEY"
from_env: true