10 min read

Devbox: Instant, Reproducible Development Environments

Say goodbye to “works on my machine” problems. Learn how Devbox uses Nix to create instant, reproducible development environments that work consistently across your entire team.

DevBox: The Future of Isolated Development Environments

Key Takeaways

  • Devbox creates isolated, reproducible development environments using Nix, without requiring you to learn Nix.
  • A simple devbox.json file defines all project dependencies, ensuring consistency across development machines.
  • Devbox offers faster startup times and lower resource usage compared to Docker or Vagrant for local development.
  • Built-in services support allows running databases and other background processes with zero configuration.

What is Devbox?

Devbox is a command-line tool that creates isolated, reproducible development environments for any project. Built by Jetpack.io, it uses Nix to provide instant, portable shells with all the tools and dependencies your project needs.

The core problem Devbox solves is environment consistency. How many times have you heard “it works on my machine”? Different developers have different versions of Node, Python, or Go installed. System libraries vary between macOS and Linux. Dependencies conflict between projects. Devbox eliminates these issues entirely.

“Devbox creates isolated shells for development. You can define the list of packages required for your project, and Devbox will install them in a local directory and create an isolated shell environment.”

— Jetpack.io Documentation

Unlike Docker, which creates containerised environments, Devbox runs packages natively on your machine. This means faster startup times, direct access to your filesystem, and smooth integration with your existing tools and IDEs.

How Devbox Works

Under the hood, Devbox uses Nix, the purely functional package manager. Nix provides several guarantees that make reproducible environments possible:

Deterministic Builds

Every package is built with its complete dependency tree, ensuring the same inputs always produce the same outputs.

Isolated Packages

Packages are stored in isolation with unique hashes. Multiple versions can coexist without conflicts.

Massive Package Repository

Nixpkgs contains over 100,000 packages, from programming languages to databases to command-line utilities.

Cross-Platform Support

The same devbox.json works on macOS, Linux, and Windows (via WSL2), ensuring true cross-platform reproducibility.

The beauty of Devbox is that it abstracts away Nix's complexity. You don't need to learn the Nix expression language or understand its package derivations. Devbox provides a simple JSON configuration and intuitive commands.

# The workflow is simple:
$ devbox init          # Create devbox.json
$ devbox add nodejs    # Add packages
$ devbox shell         # Enter the environment

# That's it! Your isolated environment is ready.

Installing Devbox

Installing Devbox is straightforward. It automatically installs Nix if needed, so you don't need to set it up separately.

Quick Install (Recommended)

# Install Devbox with the official installer
curl -fsSL https://get.jetpack.io/devbox | bash

# Verify installation
devbox version

Alternative Installation Methods

# Using Homebrew (macOS/Linux)
brew install jetpack-io/devbox/devbox

# Using Nix (if you already have Nix installed)
nix-env -iA nixpkgs.devbox

# Using Nixpkgs flakes
nix profile install nixpkgs#devbox

Note for Windows Users

Devbox requires WSL2 on Windows. Install WSL2 first, then run the installation command inside your WSL2 distribution.

Creating devbox.json

The devbox.json file is the heart of your Devbox configuration. It defines packages, environment variables, shell hooks, and scripts for your project.

Initialising a New Project

# Navigate to your project directory
cd my-project

# Initialise Devbox
devbox init

# This creates devbox.json and devbox.lock

Example devbox.json

{
  "$schema": "https://raw.githubusercontent.com/jetpack-io/devbox/main/.schema/devbox.schema.json",
  "packages": [
    "nodejs@20",
    "python@3.12",
    "postgresql@15",
    "redis@7"
  ],
  "env": {
    "DATABASE_URL": "postgresql://localhost:5432/myapp_dev",
    "REDIS_URL": "redis://localhost:6379",
    "NODE_ENV": "development"
  },
  "shell": {
    "init_hook": [
      "echo 'Welcome to the development environment!'",
      "export PATH=$PWD/node_modules/.bin:$PATH"
    ],
    "scripts": {
      "dev": "npm run dev",
      "test": "npm test",
      "lint": "eslint . --ext .ts,.tsx",
      "db:migrate": "prisma migrate dev",
      "db:seed": "prisma db seed"
    }
  }
}

The devbox.lock file is generated automatically and pins exact package versions. Always commit both files to version control for reproducibility.

Adding Packages

Devbox provides access to over 100,000 packages from the Nixpkgs repository. Usedevbox add to install packages.

Basic Package Management

# Add a package (latest version)
devbox add nodejs

# Add a specific version
devbox add nodejs@20
devbox add python@3.12.1

# Add multiple packages at once
devbox add go@1.21 rustc cargo

# Search for packages
devbox search postgresql

# Remove a package
devbox rm nodejs

# List installed packages
devbox list

Common Package Examples

# Web Development
devbox add nodejs@20 yarn pnpm typescript

# Python Development
devbox add python@3.12 poetry pipenv

# Go Development
devbox add go@1.21 golangci-lint gopls

# Rust Development
devbox add rustc cargo rust-analyzer

# DevOps Tools
devbox add terraform kubectl helm awscli

# Databases
devbox add postgresql@15 mysql@8 redis@7 mongodb@6

# Utilities
devbox add git jq yq ripgrep fd curl wget

Finding Package Names

Use devbox search <name> to find available packages, or browse the Nixpkgs repository at search.nixos.org/packages.

Local vs Global Configuration

Devbox supports two configuration scopes: local (project-level) and global (user-level). Understanding when to use each helps you organise your development tools effectively.

Local (Project)

Project-specific packages defined in devbox.json at the repository root. Shared with your team via version control.

  • Project-specific language runtimes (Node, Python, Go)
  • Databases and services needed for the project
  • Build tools and project dependencies
  • Committed to git, shared across team

Global (User)

User-wide packages available in any terminal session. Stored in~/.local/share/devbox/global.

  • General CLI tools (ripgrep, jq, fd, bat)
  • Cloud CLIs (aws, gcloud, az)
  • Infrastructure tools (terraform, kubectl)
  • Personal to your machine, not shared

Setting Up Global Devbox

Global packages are available system-wide without entering a project-specific shell. Perfect for tools you use across all projects.

# Add packages globally
devbox global add ripgrep fd bat jq yq
devbox global add terraform kubectl helm
devbox global add awscli google-cloud-sdk azure-cli

# List global packages
devbox global list

# Remove a global package
devbox global rm terraform

# View global configuration path
devbox global path
# Output: ~/.local/share/devbox/global

# Edit global devbox.json directly
devbox global edit

Activating Global Packages

To make global packages available in every terminal session, add the shellenv to your shell profile:

# For Zsh (add to ~/.zshrc)
eval "$(devbox global shellenv)"

# For Bash (add to ~/.bashrc)
eval "$(devbox global shellenv)"

# For Fish (add to ~/.config/fish/config.fish)
devbox global shellenv | source

# Reload your shell
source ~/.zshrc  # or ~/.bashrc

Global Configuration File

The global configuration works just like project configuration but applies everywhere:

# ~/.local/share/devbox/global/devbox.json
{
  "$schema": "https://raw.githubusercontent.com/jetpack-io/devbox/main/.schema/devbox.schema.json",
  "packages": [
    "ripgrep@14",
    "fd@9",
    "bat@0.24",
    "jq@1.7",
    "yq@4",
    "terraform@1.6",
    "kubectl@1.28",
    "awscli2@2",
    "git@2.43",
    "gh@2"
  ],
  "env": {
    "EDITOR": "vim",
    "AWS_PAGER": ""
  },
  "shell": {
    "init_hook": [
      "# Global shell customisations",
      "alias ll='ls -la'",
      "alias k='kubectl'",
      "alias tf='terraform'"
    ]
  }
}

Local Project Configuration

Local configuration is stored in your project directory and should be committed to git:

# Create local config in your project
cd ~/projects/my-web-app
devbox init

# Add project-specific packages
devbox add nodejs@20 pnpm typescript
devbox add postgresql@15 redis@7

# Your project now has:
# ./devbox.json    - Configuration (commit this)
# ./devbox.lock    - Lock file (commit this)

# Enter the project shell
devbox shell

# Packages from BOTH local and global are available!
node --version    # From local config
rg --version      # From global config

How Local and Global Interact

When you run devbox shell in a project directory, Devbox combines packages from both local and global configurations:

  • Local packages take precedence if there's a version conflict
  • Global packages are available as a fallback for common tools
  • Environment variables from both are merged (local wins on conflict)
  • Init hooks from both are executed (global first, then local)
# Example workflow
$ devbox global add ripgrep jq      # Available everywhere
$ cd ~/projects/api
$ devbox init
$ devbox add nodejs@20 postgresql   # Only in this project

$ devbox shell
# Now you have: nodejs, postgresql (local) + ripgrep, jq (global)

$ cd ~/projects/python-app
$ devbox init
$ devbox add python@3.12 poetry     # Only in this project

$ devbox shell
# Now you have: python, poetry (local) + ripgrep, jq (global)
# nodejs is NOT available here - it was local to the api project

Shell Hooks and Init Hooks

Hooks allow you to run commands automatically when entering the Devbox shell. Use them to set up your environment, display welcome messages, or run initialisation scripts.

Init Hook Configuration

{
  "packages": ["nodejs@20", "python@3.12"],
  "shell": {
    "init_hook": [
      "# Display environment info",
      "echo '🚀 Development environment ready!'",
      "echo 'Node version:' $(node --version)",
      "echo 'Python version:' $(python --version)",
      "",
      "# Set up Python virtual environment",
      "if [ ! -d .venv ]; then",
      "  python -m venv .venv",
      "fi",
      "source .venv/bin/activate",
      "",
      "# Install dependencies if needed",
      "if [ -f package.json ] && [ ! -d node_modules ]; then",
      "  npm install",
      "fi",
      "",
      "# Add local bin to PATH",
      "export PATH=$PWD/node_modules/.bin:$PWD/.venv/bin:$PATH"
    ]
  }
}

Using External Scripts

For complex setup logic, reference an external script file:

{
  "packages": ["nodejs@20"],
  "shell": {
    "init_hook": [
      ". ./scripts/devbox-init.sh"
    ]
  }
}
# scripts/devbox-init.sh
#!/bin/bash

# Load environment-specific configuration
if [ -f .env.local ]; then
  export $(cat .env.local | xargs)
fi

# Check for required tools
command -v docker >/dev/null 2>&1 || echo "⚠️  Docker not found"

# Set up git hooks
if [ -d .git ]; then
  git config core.hooksPath .githooks
fi

echo "✅ Environment initialised successfully"

Environment Variables

Devbox allows you to define environment variables that are automatically set when entering the shell. This is useful for configuration that should be consistent across all development machines.

{
  "packages": ["nodejs@20", "postgresql@15"],
  "env": {
    "NODE_ENV": "development",
    "LOG_LEVEL": "debug",
    "DATABASE_URL": "postgresql://localhost:5432/myapp_dev",
    "API_BASE_URL": "http://localhost:3000",
    "CACHE_TTL": "3600",
    
    "# You can reference other variables",
    "APP_NAME": "my-application",
    "DATA_DIR": "$PWD/data"
  }
}

Sensitive Variables

Never commit sensitive values like API keys or passwords to devbox.json. Use init_hook to load them from a local .env file that's git-ignored.

Devbox Shell vs Devbox Run

Devbox provides two ways to execute commands: interactive shell and direct execution. Understanding when to use each is key to an efficient workflow.

devbox shell

Opens an interactive shell with all packages available. Best for development sessions where you'll run multiple commands.

$ devbox shell

devbox run

Executes a single command or script and exits. Best for CI/CD, automation, and one-off commands.

$ devbox run test

Defining Scripts

{
  "packages": ["nodejs@20", "postgresql@15"],
  "shell": {
    "scripts": {
      "dev": "npm run dev",
      "build": "npm run build",
      "test": "npm test",
      "test:watch": "npm test -- --watch",
      "lint": "eslint . --ext .ts,.tsx",
      "format": "prettier --write .",
      "db:start": "pg_ctl start",
      "db:stop": "pg_ctl stop",
      "db:migrate": "prisma migrate dev",
      "clean": "rm -rf node_modules dist .next"
    }
  }
}

Usage Examples

# Run a defined script
devbox run dev
devbox run test
devbox run db:migrate

# Run an arbitrary command
devbox run -- npm install lodash
devbox run -- python -c "print('Hello from Devbox')"

# Chain commands
devbox run -- npm install && npm test

# Use in CI/CD
devbox run build
devbox run test

Devbox Services

Devbox can manage background services like databases, message queues, and caches. Services are defined in devbox.json and managed with simple commands.

Enabling Services

{
  "packages": [
    "postgresql@15",
    "redis@7",
    "nginx"
  ],
  "env": {
    "PGDATA": "$PWD/.devbox/virtenv/postgresql/data",
    "PGHOST": "$PWD/.devbox/virtenv/postgresql",
    "REDIS_DATA": "$PWD/.devbox/virtenv/redis"
  }
}

Managing Services

# Start all services
devbox services start

# Start specific services
devbox services start postgresql
devbox services start redis

# Check service status
devbox services ls

# Stop services
devbox services stop

# Restart services
devbox services restart postgresql

# View service logs
devbox services logs postgresql

Custom Service Configuration

For services that require custom configuration, create a process-compose.yaml file:

# process-compose.yaml
version: "0.5"

processes:
  web:
    command: npm run dev
    availability:
      restart: on-failure
    depends_on:
      postgresql:
        condition: process_healthy
        
  worker:
    command: npm run worker
    availability:
      restart: on-failure
    depends_on:
      redis:
        condition: process_healthy

  postgresql:
    command: postgres -D $PGDATA
    readiness_probe:
      exec:
        command: pg_isready
      initial_delay_seconds: 2
      period_seconds: 5
        
  redis:
    command: redis-server
    readiness_probe:
      exec:
        command: redis-cli ping
      initial_delay_seconds: 1
      period_seconds: 3

Devbox vs Docker vs Vagrant

Each tool serves different purposes. Understanding their trade-offs helps you choose the right tool for your needs.

FeatureDevboxDockerVagrant
Setup TimeSeconds (cached packages)Minutes (image builds)Minutes to hours (VM provisioning)
Resource UsageMinimal (native processes)Low-Medium (containerised)High (full VM)
ReproducibilityExcellent (Nix guarantees)Good (image layers)Good (provisioning scripts)
Learning CurveLow (simple JSON config)Medium (Dockerfile, compose)Medium (Vagrantfile, provisioners)
Host IntegrationNative (no isolation)Limited (volume mounts)Limited (shared folders)
Package Availability100,000+ Nix packagesDepends on base imageDepends on provisioner

When to Use Each

  • Devbox: Local development, quick project setup, team environment consistency
  • Docker: Production deployments, microservices, when you need process isolation
  • Vagrant: Full VM requirements, testing across different operating systems

Integrating with IDEs

Devbox integrates well with popular IDEs and editors, providing a smooth development experience with the correct tools and language servers.

VS Code

Install the Devbox extension for automatic environment activation and integrated terminal support.

  1. 1Install "Devbox" extension from marketplace
  2. 2Open a project with devbox.json
  3. 3Extension auto-activates devbox environment
  4. 4Use integrated terminal with devbox shell

JetBrains IDEs

Configure JetBrains IDEs to use Devbox-managed SDKs and tools for consistent development.

  1. 1Run devbox shell to activate environment
  2. 2Note paths: which node, which python, etc.
  3. 3Configure SDK paths in IDE settings
  4. 4Set terminal to run devbox shell on startup

Neovim / Vim

Integrate with direnv for automatic environment loading when entering project directories.

  1. 1Install direnv and enable devbox integration
  2. 2Run devbox generate direnv in project
  3. 3Add direnv hook to shell configuration
  4. 4Environment loads automatically on cd

Direnv Integration

Direnv automatically loads the Devbox environment when you enter the project directory:

# Generate direnv configuration
devbox generate direnv

# This creates .envrc with:
# eval "$(devbox generate direnv --print-envrc)"

# Allow direnv for this directory
direnv allow

# Now the environment loads automatically on cd!

Best Practices

Follow these best practices to get the most out of Devbox in your projects and teams.

Project Configuration

  • Commit devbox.json and devbox.lock to version control
  • Use specific package versions for critical dependencies
  • Document any required init_hook setup in README
  • Keep devbox.json at the repository root for discoverability

Team Collaboration

  • Ensure all team members use devbox shell for development
  • Use devbox services for shared local services like databases
  • Create scripts for common development tasks using devbox run
  • Document IDE integration steps for your team

CI/CD Integration

  • Use devbox in CI pipelines for consistent build environments
  • Cache the Nix store between CI runs for faster builds
  • Run tests inside devbox shell to match local behaviour
  • Use devbox run for reproducible build commands

Performance

  • Use devbox global for frequently used tools across projects
  • Use Nix binary caches for faster package downloads
  • Avoid unnecessary packages to keep environments lean
  • Use shell hooks sparingly to minimise startup time

Troubleshooting

Common issues and solutions when working with Devbox.

Nix Store Disk Space Issues

Symptom: Disk space filling up, slow package installations.

Common causes:

  • Old package versions not garbage collected
  • Multiple projects with different package versions
  • Build artifacts accumulating in store

Solution:

# Check Nix store size
du -sh /nix/store

# Run garbage collection
nix-collect-garbage -d

# Remove old generations (keeps last 7 days)
nix-collect-garbage --delete-older-than 7d

# Optimise store by hard-linking identical files
nix-store --optimise

Shell Not Activating Properly

Symptom: Commands not found after running devbox shell, or wrong versions used.

Common causes:

  • PATH not updated correctly
  • Shell init scripts overriding Devbox PATH
  • Conflicting shell configurations
  • Nested shell sessions

Solution:

# Verify devbox shell is active
echo $DEVBOX_SHELL_ENABLED

# Check PATH includes Nix packages
echo $PATH | tr ':' '\n' | grep nix

# Use devbox run for isolated command execution
devbox run -- node --version

# Debug shell activation
devbox shell --print-env

# Clear and reinstall if needed
devbox services stop && devbox rm && devbox install

Package Not Found or Version Unavailable

Error: “Package not found in nixpkgs” or version mismatch.

Common causes:

  • Package name different in nixpkgs
  • Specific version not available
  • Package in unfree or unstable channel

Solution:

# Search for package name
devbox search nodejs
devbox search python3

# Use specific version with @
devbox add nodejs@20
devbox add python@3.11

# Search nixpkgs directly
nix-env -qaP '.*nodejs.*'

# For unfree packages, add to devbox.json
{
  "nixpkgs": {
    "config": {
      "allowUnfree": true
    }
  }
}

Services Not Starting

Symptom: devbox services start fails or services immediately stop.

Common causes:

  • Port already in use
  • Missing configuration files
  • Permission issues on data directories
  • Service definition errors in process-compose.yaml

Solution:

# Check service status
devbox services ls

# View service logs
devbox services logs postgresql

# Check for port conflicts
lsof -i :5432

# Restart services cleanly
devbox services stop
devbox services start

# Debug process-compose
devbox services start --debug

Devbox Slow on macOS

Symptom: devbox shell takes long to start, or commands are slow.

Common causes:

  • First-time package downloads
  • Rosetta translation on Apple Silicon
  • Large number of packages in environment
  • Antivirus scanning Nix store

Solution:

# Use native ARM packages on Apple Silicon
# Devbox handles this automatically, but verify:
uname -m  # Should show arm64

# Exclude /nix from antivirus scanning
# Add /nix to your antivirus exclusion list

# Pre-install packages before entering shell
devbox install

# Use devbox run for one-off commands (faster startup)
devbox run -- npm test

Conclusion

Devbox represents a significant step forward in developer experience. By using Nix's package management whilst hiding its complexity, Devbox makes reproducible development environments accessible to everyone.

The benefits are clear:

  • Instant setup: New team members can be productive in minutes, not hours.
  • True reproducibility: The same environment on every machine, guaranteed by Nix.
  • Low overhead: Native execution without containers or VMs means minimal resource usage.
  • Simple configuration: A single JSON file defines your entire development environment.

Whether you're working on a personal project or managing development environments for a large team, Devbox provides the tools to eliminate environment inconsistencies and focus on what matters: writing great code.

Frequently Asked Questions

Devbox is a command-line tool that creates isolated, reproducible development environments for any project. Built by Jetpack.io, it uses the Nix package manager to provide instant, portable shells with all the tools and dependencies your project needs, without requiring you to learn Nix itself.

While Docker creates containerised environments with process isolation, Devbox runs packages natively on your machine. This means faster startup times (seconds vs minutes), lower resource usage, direct filesystem access, and smooth integration with your IDE. Docker is better suited for production deployments and when you need true process isolation, whereas Devbox excels at local development environments.

Nix is a purely functional package manager that provides deterministic builds and isolated packages. Devbox uses Nix under the hood to access over 100,000 packages from the Nixpkgs repository. The key benefit is that Devbox abstracts away Nix complexity – you configure your environment with a simple devbox.json file instead of learning the Nix expression language.

Shell hooks (specifically init_hook in devbox.json) are commands that run automatically when you enter the Devbox shell. They are useful for setting up your environment, such as activating Python virtual environments, installing dependencies, setting PATH variables, or displaying welcome messages. You can define them as an array of shell commands in your configuration.

Yes, Devbox has built-in services support for running background processes like databases (PostgreSQL, Redis, MySQL), message queues, and web servers. Use "devbox services start" to start all configured services, "devbox services ls" to check their status, and "devbox services logs" to view logs. For complex service configurations, you can create a process-compose.yaml file.

Simply commit the devbox.json and devbox.lock files to your version control repository. The devbox.json defines your packages, environment variables, and scripts, while devbox.lock pins exact package versions for reproducibility. Team members only need to install Devbox and run "devbox shell" to get the identical development environment.

References & Further Reading

Related Articles

Ayodele Ajayi

Principal Engineer based in Kent, UK. Specialising in security governance, cloud architecture, and platform engineering.