Everyone Acts Like VS Code Owns Devcontainers
Here’s the thing: VS Code’s Remote Containers extension marketed devcontainers so hard that most folks think they’re a Microsoft-only invention. They’re not. A devcontainer is just a standardized config file—devcontainer.json—that describes a containerized dev environment. Any tool that understands the spec can spin one up.
VS Code just made it look shiny first.
If you’re running neovim, tmux, or any terminal-based editor, you don’t have to abandon devcontainers. You don’t have to SSH into a Compose stack or run Docker commands manually. There’s a better path: DevPod.
DevPod is an open-source CLI tool that treats devcontainers as a first-class concept—agnostic to your editor. Spin up an isolated, reproducible dev environment in seconds. Tear it down when you’re done. No VS Code required. No lock-in. Pure command-line bliss.
What Devcontainers Actually Are
Before we jump to the tool, let’s nail the concept. A devcontainer is three things:
- A container image — your dev environment packaged up. Python 3.13, Node 22, Ruby, whatever.
- A config file (
devcontainer.json) — specifies the image, mount points, environment variables, and which dev tools to install inside the container. - Mounted source code — your local repo synced into the container so you can edit locally and have your editor talk to tools inside.
That’s it. It’s not magic. It’s just Docker Compose with a standardized manifest.
Why This Matters
Imagine you’re jumping between three projects:
- Project A needs Postgres 15 + Go 1.22
- Project B needs Node 18 + Redis 7
- Project C is Python 3.10 + Postgres 16
Without devcontainers, you’re either:
- Installing everything globally and praying version conflicts don’t explode (they will, at 2 AM)
- Spinning up manual Docker networks and managing port chaos
- Using asdf/nvm/pyenv and maintaining per-project version files
With devcontainers, you cd into each project and your whole environment—versions, tools, everything—materializes. No pollution. No cross-project contamination. Your system stays clean.
The Devcontainer.json Schema
Here’s a minimal example:
{ "name": "my-python-project", "image": "mcr.microsoft.com/devcontainers/python:1.3-3.12-bullseye", "features": { "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}, "ghcr.io/devcontainers/features/github-cli:1": {} }, "forwardPorts": [8000, 5432], "postCreateCommand": "pip install -r requirements.txt", "remoteUser": "vscode", "mounts": [ "source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,readonly", "source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,readonly" ]}Let’s break this down:
name— friendly identifier for your environment. Appears in DevPod listings.image— the base Docker image. Microsoft publishes pre-built devcontainer images (Python, Node, Go, etc.). You can use your own too.features— optional bundles that install common tools.docker-outside-of-dockerlets you run Docker inside the container.github-cliinstalls the gh command.forwardPorts— ports exposed from the container to localhost. Solocalhost:8000hits your app running inside.postCreateCommand— shell command that runs once after the container launches. Perfect forpip install,npm install, or running setup scripts.remoteUser— which user inside the container runs your shell. The standard images usevscode; you can change it.mounts— bind mounts from your host machine into the container. Here we’re mounting your SSH keys and Git config read-only so you can commit without re-entering credentials.
There are dozens more fields—customizations (editor-specific settings), remoteEnv (container-side env vars), containerEnv, onCreateCommand, and so on. The full spec is your reference.
Enter DevPod: The Editor-Agnostic Solution
DevPod is a Loft Labs project that abstracts away the editor. Instead of VS Code Extension orchestrating containers, DevPod’s CLI does it. You manage devcontainers from your terminal, then connect any editor you want.
Installation
# macOS / Linuxcurl -fsSL https://devpod.sh/install.sh | sh
# Verifydevpod --versionDevPod stores config in ~/.devpod/ and metadata in .devpod/ inside each project.
The DevPod Workflow
1. Initialize a devcontainer in a new (or existing) project:
cd my-projectdevpod up --initDevPod prompts you:
- Which provider? (Docker, Kubernetes, SSH, cloud options like AWS)
- Which devcontainer preset? (Python, Node, Go, etc.) or custom image?
- Which IDE? (VS Code, JetBrains, neovim, none)
If you choose “none”, DevPod sets up the container without trying to inject editor configs.
2. Start the devcontainer:
devpod upDevPod:
- Builds/pulls the image
- Launches the container with your source code mounted
- Runs any
postCreateCommandhooks - Sits waiting for you to connect
3. SSH into the running container:
devpod ssh my-projectYou’re now inside. Your editor runs locally, but tools (compilers, linters, language servers) are inside the container. Your $PATH inside includes everything the Dockerfile installed.
4. Use neovim or any editor as normal:
Inside the SSH session, just fire up neovim:
nvim src/main.pyYour neovim talks to the Python language server running inside the container. LSP over SSH works flawlessly.
5. Tear down when done:
devpod downContainer stops, image and mounts cleaned up (unless you keep them for next time).
Neovim + DevPod: The Real Power Move
Here’s the workflow that’ll make you forget VS Code exists:
1. Create a .devcontainer/devcontainer.json
{ "name": "rust-project", "image": "mcr.microsoft.com/devcontainers/rust:latest", "features": { "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {} }, "postCreateCommand": "rustup component add rust-analyzer", "forwardPorts": [8080], "remoteUser": "vscode"}2. Start the devcontainer
devpod up# Choose Docker, confirm settings, container boots3. Drop into a shell inside the container
devpod ssh4. Launch neovim
nvim src/main.rsBecause rust-analyzer and Cargo are installed inside the container, your LSP works over SSH. Diagnostics, go-to-definition, autocomplete—all responsive.
5. Terminal stays connected
Open a split in tmux:
# First pane: neovimnvim src/main.rs
# Second pane: same shellcargo buildcargo testBoth talk to the container seamlessly.
Why This Beats Manual Setup
- No install pollution. Your Mac/Linux stays clean. Every devcontainer is ephemeral by default.
- Reproducibility. Colleague clones the repo, runs
devpod up, gets identical environment. No “works on my machine” excuses. - Language matrices. Testing against Python 3.11 and 3.12? Use different devcontainer configs in branches. CI can do the same.
- Fresh starts. Accidentally broke something inside?
devpod down && devpod upand you’re back to a clean state.
Real Talk: When Devcontainers Might Be Overkill
If your project is dead simple—vanilla Node app with zero native dependencies—spinning up a whole container might feel heavy. A single global node binary is fine.
But the moment you have:
- Multiple services (database, cache, message queue)
- Version-specific compilation (Rust, Go, C)
- System-level dependencies (ffmpeg, imagemagick)
- A team that spans macOS, Linux, and Windows
…devcontainers save you days of onboarding friction.
The Deeper Win: Language Matrices Without Docker Compose Hell
Here’s where devcontainers really shine for teams:
Create multiple configs:
.devcontainer/ python-3.11/devcontainer.json python-3.12/devcontainer.json python-3.13/devcontainer.jsonEach one specifies a different base image:
{ "image": "python:3.11", "postCreateCommand": "pip install -r requirements.txt && pytest"}Now your CI pipeline can test all three versions:
strategy: matrix: python-version: [3.11, 3.12, 3.13]steps: - run: devpod up --folder .devcontainer/python-${{ matrix.python-version }} - run: devpod ssh -- pytest - run: devpod downNo duplicate Compose files. No version sprawl. One .devcontainer/ directory that scales.
The Missing Piece: Keep Your Dotfiles in Sync
DevPod mounts your source code, but you probably want your neovim config, tmux settings, and shell history inside the container too.
Mount your dotfiles repo in devcontainer.json:
{ "mounts": [ "source=${localEnv:HOME}/.config/nvim,target=/home/vscode/.config/nvim,readonly", "source=${localEnv:HOME}/.tmux.conf,target=/home/vscode/.tmux.conf,readonly", "source=${localEnv:HOME}/.zshrc,target=/home/vscode/.zshrc,readonly" ]}Now when you SSH in, your editor and shell feel exactly like home. No context switching.
The Verdict
VS Code’s devcontainers are excellent, but they’re not the only game in town. If you’re a terminal person—neovim, tmux, ssh—DevPod frees you from the VS Code extension ecosystem without sacrificing the reproducibility that devcontainers offer.
You get:
- Standardized environments (the whole point of devcontainers)
- Clean separation between your system and projects
- The editor you actually want to use
- CLI-first workflows that play nice with scripts and CI pipelines
No lock-in. No Extension Marketplace dependency. Just a simple JSON file and a container.
That’s the real power of open standards.