I'm primarily a solo developer, but in the last few months I've been working with external freelancers in Antigravity more often. What happened in week one: daily messages of "doesn't work on my end."
The causes were mundane — Node.js version mismatches, Python virtualenv differences, linter config load order, shell-induced PATH variations. Things I never noticed when only I touched the environment surfaced all at once in collaboration.
To fix this structurally, I adopted DevContainers in my Antigravity projects. The result: "open Antigravity, everyone develops inside the exact same Docker container." Environment-divergence troubles plummeted. Here's the configuration and operational notes.
What DevContainers Are and Why They Click With Antigravity
DevContainers grew up in the VS Code ecosystem. You declare a container in .devcontainer/devcontainer.json and the editor runs your development inside that container. Antigravity is a VS Code-family editor, so the mechanism just works.
"Couldn't you just use Docker?" — yes, but DevContainers' real value is that the editor handles container setup, launch, mount points, and extension installation for you. Team members do "clone the repo, open in Antigravity" and get the same environment with zero setup.
This pays off for solo developers using multiple machines too. I work across desktop, MacBook, and a home Mac mini — keeping Node.js, Python, and friends in sync on three machines was honestly tedious. After containerizing, any machine with Docker just works.
Minimal devcontainer.json
Start minimal. Create .devcontainer/devcontainer.json at project root.
{
"name": "My Antigravity Project",
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
"postCreateCommand": "npm install",
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
}
}That's it. Open the project in Antigravity and a "Reopen in Container?" dialog appears. Yes, and Antigravity rebuilds and runs inside the container. npm install runs automatically and the ESLint and Prettier extensions are auto-installed.
The image field references a Microsoft-published standard image. For TypeScript + Node.js the one above is convenient. Python: mcr.microsoft.com/devcontainers/python:3.12. Go: mcr.microsoft.com/devcontainers/go:1.22.
This alone guarantees "everyone uses the same Node.js version." That single guarantee resolved half the disputes I was having.
Practical Setup — Multi-Service
Real projects need a database, Redis, etc. Add a docker-compose.yml.
.devcontainer/docker-compose.yml:
services:
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ..:/workspaces/${localWorkspaceFolderBasename}:cached
command: sleep infinity
environment:
- DATABASE_URL=postgres://dev:dev@db:5432/devdb
- REDIS_URL=redis://redis:6379
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_USER: dev
POSTGRES_PASSWORD: dev
POSTGRES_DB: devdb
volumes:
- postgres-data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
postgres-data:.devcontainer/Dockerfile:
FROM mcr.microsoft.com/devcontainers/typescript-node:20
RUN apt-get update && apt-get install -y \
postgresql-client \
redis-tools \
&& rm -rf /var/lib/apt/lists/*
USER node.devcontainer/devcontainer.json:
{
"name": "My Antigravity Project",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
"postCreateCommand": "npm install && npm run db:migrate",
"forwardPorts": [3000, 5432, 6379],
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"ckolkman.vscode-postgres"
]
}
}
}Now opening Antigravity launches the app container, PostgreSQL, and Redis simultaneously. The app reaches PostgreSQL at hostname db and Redis at hostname redis.
postCreateCommand runs migrations automatically, so a new teammate cloning the repo and opening Antigravity gets "deps installed → DB up → migrations done" for free. This is genuinely powerful.
Gotcha 1: File Ownership
The first wall after adopting DevContainers: file ownership. Container user (often node or vscode) and host user have different UIDs, so files created inside the container show up "readable but not writable" on the host.
Fix: align the container user's UID to the host. Inside the Dockerfile:
ARG USER_UID=1000
ARG USER_GID=1000
RUN if [ "$USER_UID" != "1000" ]; then \
usermod -u $USER_UID node && \
groupmod -g $USER_GID node; \
fiPass UID/GID via build.args in devcontainer.json:
{
"build": {
"dockerfile": "Dockerfile",
"args": {
"USER_UID": "${localEnv:UID}",
"USER_GID": "${localEnv:GID}"
}
}
}This avoids ownership issues on Linux hosts. On macOS, Docker Desktop handles UID mapping nicely so you rarely hit this.
Gotcha 2: Antigravity Extensions — Server-Side vs Client-Side
In DevContainers, some extensions run on the container side and some on the local side. Antigravity's AI features run locally; language tools like linters run in the container.
The problem: some Antigravity-bundled plugins might "install on container side when they should be local-side" or vice versa. Features stop working or double-run.
Fix: in customizations.vscode.extensions, list only the things that should run in the container. Skip AI-side plugins and Antigravity-specific UI extensions. Stick to language servers, formatters, linters — anything tied to the project's language.
Gotcha 3: File Watch Limits
Heavy file-watching tasks (webpack-dev-server, Vite HMR) inside DevContainers can hit the Linux host's inotify ceiling. The error reads ENOSPC: System limit for number of file watchers reached.
Fix: relax the limit via Dockerfile or devcontainer.json.
{
"containerEnv": {
"CHOKIDAR_USEPOLLING": "false"
},
"runArgs": [
"--sysctl", "fs.inotify.max_user_watches=524288"
]
}CHOKIDAR_USEPOLLING=true switches to polling and avoids inotify, but burns CPU — not recommended. Raising the cap via runArgs is cleaner.
Team Operation Best Practices
Operational notes from running this with teams:
Always discuss .devcontainer/ changes via PR. Casual edits trigger a 20-minute container rebuild for everyone next time they open the project. The team needs a shared sense of how expensive these changes are.
Make postCreateCommand idempotent. npm install is idempotent so it's fine, but commands with side effects like migrations need "skip if already done" logic. Or use postCreateCommand (runs only on container creation) instead of postStartCommand to limit blast radius.
Tell the team about "Rebuild Container." When the container goes weird, the Antigravity command palette has "Rebuild Container" — rebuild from scratch. Just knowing this exists shaves hours off recovery time.
When Not to Use DevContainers
Honestly, not every project benefits.
Short-lived prototypes and solo-only tools — the setup overhead isn't worth it. Container startup is also a couple of minutes, and that latency may not be worth losing for the convenience tradeoff.
Native GUI development (Electron apps, mobile dev with simulators) is also a bad fit. X11 forwarding is possible but adds significant complexity.
My personal rule: containerize if any of these hold — "3+ people will touch it," "lifespan of 6+ months," "uses peripheral services like a DB or queue."
Tomorrow's Steps
Smallest path to try tomorrow:
Create .devcontainer/devcontainer.json at the root of an existing Antigravity project; paste in the minimal example. Install Docker Desktop (or Docker Engine on Linux). Restart Antigravity or pick "Reopen in Container" from the command palette — the container builds and launches.
That's 30 minutes to an hour, though the first launch downloads images so brew coffee and wait. Subsequent launches take seconds.
The relief of "works on my machine" disappearing is bigger than I expected. Collaboration friction drops, new-member onboarding shrinks from half a day to five minutes. Once you taste it, projects without DevContainers start to feel old-fashioned.