Post

Docker Sandboxes for Claude Code: What Works and What Doesn't

I tried to run Claude Code in Docker Sandboxes for Next.js development. Here's what actually works, what doesn't, and what you should use instead.

Docker Sandboxes for Claude Code: What Works and What Doesn't

I wanted a simple thing: run Claude Code in a sandboxed container, point it at a Next.js project, forward port 3000 to my browser, and let it work. Docker Sandboxes seemed like the obvious answer.

It wasn’t.

Here’s what I learned after trying to make this work, and what you should actually use instead.

What Docker Sandboxes Is

Docker Desktop 4.58+ ships with docker sandbox, a CLI plugin that runs AI coding agents inside lightweight microVMs — not regular containers. Each sandbox gets its own kernel, its own Docker daemon, and its own isolated network namespace.

1
2
3
4
5
6
7
8
9
10
11
# Launch Claude Code in the current directory
docker sandbox run claude .

# Name your sandbox
docker sandbox run --name my-project claude .

# Reconnect to an existing sandbox
docker sandbox run my-project

# List all sandboxes
docker sandbox ls

Your project files sync bidirectionally between host and sandbox. Claude runs with --dangerously-skip-permissions by default, which is fine because the microVM itself is the security boundary. It runs as a non-root agent user with sudo access.

This part works well.

What Doesn’t Work: Port Forwarding

Here’s the wall. If you’re building a web app, you need to see it in your browser. Docker Sandboxes has no port forwarding.

There’s no -p flag. There’s no --port flag. The docker sandbox run command accepts exactly three flags: --name, --template, and --load-local-template. That’s it.

This isn’t a missing feature — it’s by design. The microVM architecture enforces strict network isolation. Sandboxes can’t reach your host’s localhost, and your host can’t reach into the sandbox. The network policy system (docker sandbox network proxy) only controls outbound traffic.

So when Claude runs npm run dev inside the sandbox, the Next.js dev server starts and runs perfectly — you just can’t see it.

What Else Doesn’t Work

If you’re coming from docker run, most of the flags you’re used to don’t exist on docker sandbox run:

Flag docker run docker sandbox run
-p 3000:3000 Works Does not exist
-v ~/.claude:/root/.claude Works Does not exist
-e HOME=/app Works Does not exist
--user $(id -u):$(id -g) Works Does not exist
--env-file .env.local Works Does not exist
--mount .:/app Works Not needed (file sync is automatic)

Environment variables are particularly tricky. You can’t pass them with -e. Instead, you need to either set them globally before Docker Desktop starts, use docker sandbox exec --env KEY=VALUE for individual commands, or authenticate interactively inside the sandbox with /login.

What Docker Sandboxes Is Good For

Despite the limitations for web dev, Docker Sandboxes has real strengths:

  • Running untrusted code safely — the microVM boundary is much stronger than OS-level sandboxing
  • CI/CD and headless tasks — anything that doesn’t need a browser preview
  • Persistent workspaces — sandboxes survive restarts, and you can reconnect with docker sandbox run <name>
  • Full isolation — separate kernel, PID namespace, network namespace

If your workflow is “Claude writes code, I review it, then I run it locally” — Docker Sandboxes works great. The problem is specifically when you need to interact with a running dev server.

What to Use Instead: Claude Code’s Native Sandbox

Claude Code has its own built-in sandboxing that runs directly on your machine using OS-level primitives — Apple’s Seatbelt on macOS, bubblewrap on Linux. No Docker required.

Enable it with the /sandbox slash command inside Claude Code, or add this to ~/.claude/settings.json:

1
2
3
4
5
6
7
8
9
10
{
  "sandbox": {
    "enabled": true,
    "autoAllowBashIfSandboxed": true,
    "network": {
      "allowedDomains": ["github.com", "*.npmjs.org", "registry.yarnpkg.com"],
      "allowLocalBinding": true
    }
  }
}

The key setting for web dev is allowLocalBinding: true — without it, macOS Seatbelt blocks port binding and your dev server won’t start.

What the native sandbox gives you

Filesystem isolation: Claude can only write to your project directory and subdirectories. A rogue npm postinstall script can’t modify ~/.bashrc or drop files in /usr/local/bin/.

Network isolation: All network access routes through a proxy. Only domains you’ve approved in allowedDomains are reachable. New domain requests trigger a permission prompt.

Auto-allow mode: With autoAllowBashIfSandboxed: true, sandboxed commands run without permission prompts. Anthropic reports this reduces permission prompts by about 84%.

Port binding: With allowLocalBinding: true, Claude can start your Next.js dev server and you can see it at localhost:3000 in your browser. The thing Docker Sandboxes can’t do.

How the two compare

  Native Sandbox Docker Sandbox
Setup Zero (macOS) Docker Desktop required
Overhead Minimal MicroVM startup + resources
Port forwarding Yes (allowLocalBinding) No
Env vars Normal shell environment Limited
Isolation strength OS-level (strong) VM-level (stronger)
Best for Daily development Untrusted code, CI/CD

The Bottom Line

If you’re building web apps with Claude Code and need to see your dev server in the browser, use the native sandbox. It’s lighter, it works with port forwarding, and it’s already built into Claude Code.

Docker Sandboxes is the right choice when you need maximum isolation and don’t need to interact with running services — think batch processing, code generation, or CI environments.

The gap will probably close. Docker Sandboxes is new, and port forwarding is an obvious feature request. But today, for Next.js development from the command line, the native sandbox is what actually works.

This post is licensed under CC BY 4.0 by the author.