Skip to main content

Vagrant

Create reproducible, shareable local development environments. Define your VM in a Vagrantfile, commit it to Git, and every team member runs vagrant up to get an identical environment.

✓ VirtualBox / VMware / Hyper-V ✓ Declarative Vagrantfile ✓ Shell + Ansible provisioning ✓ Multi-machine environments

Installing Vagrant and VirtualBox

# macOS
brew install --cask virtualbox
brew install --cask vagrant

# Windows (with Chocolatey)
choco install virtualbox vagrant

# Linux (Ubuntu/Debian)
sudo apt-get install virtualbox
wget https://releases.hashicorp.com/vagrant/2.4.1/vagrant_2.4.1_linux_amd64.deb
sudo dpkg -i vagrant_2.4.1_linux_amd64.deb

# Verify
vagrant --version

Basic Vagrantfile

# Vagrantfile
Vagrant.configure("2") do |config|
  # Base box — Ubuntu 22.04 from Vagrant Cloud
  config.vm.box = "ubuntu/jammy64"
  config.vm.box_version = "~> 20240301.0"  # pin to a version range

  # Hostname
  config.vm.hostname = "dev-box"

  # Network: forward port 3000 on VM to 3000 on host
  config.vm.network "forwarded_port", guest: 3000, host: 3000
  config.vm.network "forwarded_port", guest: 5432, host: 5432

  # Private network (VM gets a static IP on a host-only network)
  config.vm.network "private_network", ip: "192.168.56.10"

  # Synced folder: host ./src → VM /var/www/html (NFS for performance)
  config.vm.synced_folder "./src", "/var/www/html", type: "nfs"

  # VirtualBox provider settings
  config.vm.provider "virtualbox" do |vb|
    vb.name   = "my-dev-box"
    vb.memory = "2048"
    vb.cpus   = 2
  end

  # Shell provisioner: run once on first vagrant up
  config.vm.provision "shell", inline: <<-SHELL
    apt-get update -y
    apt-get install -y nodejs npm postgresql nginx
    systemctl enable postgresql nginx
  SHELL
end

Ansible Provisioner

# Vagrantfile with Ansible provisioner
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/jammy64"

  # Ansible is installed on the HOST machine and runs against the VM
  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "provisioning/site.yml"
    ansible.groups = {
      "webservers" => ["default"],
    }
    ansible.extra_vars = {
      node_env: "development",
      app_port: 3000,
    }
    ansible.verbose = "v"
  end
end

# For environments where Ansible is NOT on the host, use ansible_local:
# config.vm.provision "ansible_local" do |ansible|
#   ansible.playbook = "provisioning/site.yml"
#   # Vagrant installs Ansible inside the VM then runs it locally
# end

Multi-Machine Vagrantfile

# Define multiple machines to simulate a real cluster
Vagrant.configure("2") do |config|

  # Web server
  config.vm.define "web" do |web|
    web.vm.box = "ubuntu/jammy64"
    web.vm.hostname = "web"
    web.vm.network "private_network", ip: "192.168.56.10"
    web.vm.provider "virtualbox" do |vb|
      vb.memory = "1024"
    end
    web.vm.provision "shell", inline: "apt-get install -y nginx && systemctl enable nginx"
  end

  # Database server
  config.vm.define "db" do |db|
    db.vm.box = "ubuntu/jammy64"
    db.vm.hostname = "db"
    db.vm.network "private_network", ip: "192.168.56.11"
    db.vm.provider "virtualbox" do |vb|
      vb.memory = "2048"
    end
    db.vm.provision "shell", inline: "apt-get install -y postgresql && systemctl enable postgresql"
  end

  # Load balancer
  config.vm.define "lb" do |lb|
    lb.vm.box = "ubuntu/jammy64"
    lb.vm.hostname = "lb"
    lb.vm.network "private_network", ip: "192.168.56.9"
    lb.vm.network "forwarded_port", guest: 80, host: 8080
    lb.vm.provision "shell", inline: "apt-get install -y haproxy"
  end
end

# vagrant up              — start all machines
# vagrant up web          — start only the web machine
# vagrant ssh web         — SSH into web machine
# vagrant status          — show all machine statuses

Vagrant Commands Cheatsheet

Command Description
vagrant up Start VM and run provisioners (first time or after destroy)
vagrant ssh SSH into the running VM
vagrant halt Gracefully shut down the VM
vagrant suspend Save VM state (hibernate) — fast resume
vagrant resume Resume from suspended state
vagrant reload Restart VM (picks up Vagrantfile changes)
vagrant reload --provision Restart and re-run all provisioners
vagrant destroy Delete VM and free disk space
vagrant status Show running/stopped status
vagrant box list List downloaded base boxes
vagrant box update Download newer version of base box
vagrant snapshot save NAME Save a named VM snapshot

Vagrant vs Docker Compose for Local Dev

Factor Vagrant (VMs) Docker Compose
Startup time 2–5 minutes (VM boot) 5–30 seconds
RAM usage High (512MB–4GB per VM) Low (containers share host kernel)
OS isolation Full (own kernel) None (shared kernel)
Matches prod Excellent for VM-based prod Excellent for container-based prod
Provisioning Shell, Ansible, Chef, Puppet Dockerfile (layered builds)
Best for OS testing, legacy apps, Ansible dev Microservices, modern app dev

Frequently Asked Questions

What is Vagrant and how does it differ from Docker for local development?▼

Vagrant manages full virtual machines (VMs) via providers like VirtualBox, VMware, or Hyper-V, each with their own kernel and OS. Docker manages lightweight containers that share the host kernel. Vagrant is better when you need: a specific OS (e.g., test on Ubuntu 22.04 from a Mac), kernel-level features, full OS testing, or when the application requires a VM (kernel modules, different filesystem, etc.). Docker is better for most microservice development since containers start in seconds, use less RAM, and Docker Compose is excellent for multi-service local stacks. Many teams replaced Vagrant with Docker Compose but Vagrant remains relevant for OS-specific testing and legacy environments.

What is a Vagrantfile and what goes in it?▼

A Vagrantfile is a Ruby script (but reads like a configuration file) that defines the virtual machine configuration: which base box to use, networking, synced folders, provisioners, and resource allocation. The Vagrantfile lives in the project root and is version-controlled so every team member gets the same environment. Key directives: config.vm.box (which OS image), config.vm.network (port forwarding or private network), config.vm.synced_folder (map host directory into VM), config.vm.provider (VirtualBox/VMware settings like RAM and CPU), and config.vm.provision (how to configure the VM: shell, Ansible, Chef, Puppet).

Where do I find Vagrant boxes?▼

Vagrant Cloud (app.vagrantup.com, formerly Vagrant Atlas) is the official registry for public Vagrant boxes. Boxes are base OS images you build your environment on top of. Popular boxes: ubuntu/jammy64 (Ubuntu 22.04), debian/bullseye64, centos/stream8, hashicorp/bionic64, bento/ubuntu-22.04 (the Bento project by Chef has well-maintained boxes). You can also build custom boxes with Packer. Boxes are versioned, so you can pin to a specific version and lock them in your Vagrantfile with config.vm.box_version.

How do synced folders work in Vagrant?▼

Synced folders share a directory between your host machine and the VM in real-time. The default sync type maps the project directory (where Vagrantfile lives) to /vagrant in the VM. For better performance, use NFS (fastest on macOS/Linux) or SMB (Windows). Example: config.vm.synced_folder './src', '/var/www/html', type: 'nfs'. This means you edit code in your IDE on the host, and the VM immediately sees the changes — no SSH copy needed. Some boxes do not include VirtualBox Guest Additions by default (needed for VirtualBox synced folders), so the vagrant-vbguest plugin auto-installs them.

What are the most commonly used Vagrant commands?▼

vagrant up — start and provision the VM (or resume if suspended). vagrant ssh — SSH into the running VM. vagrant halt — shut down the VM (preserves disk state). vagrant suspend — save VM state to disk (like hibernation, faster resume than halt). vagrant resume — resume from suspended state. vagrant reload — restart VM and re-run provisioners. vagrant reload --provision — force re-run all provisioners. vagrant destroy — delete the VM entirely (frees disk space). vagrant status — show VM status. vagrant box update — download newer version of the base box. vagrant provision — re-run provisioners without restarting.

How does Vagrant compare to Docker Compose for local development?▼

Docker Compose is now the default for most modern microservice development: faster startup (seconds vs minutes), lower resource usage (containers vs full VMs), easy multi-service networking, and tight integration with the container ecosystem. Vagrant is better when you specifically need full VM isolation, a different kernel or OS from your host, or are replicating a production VM environment. Some teams use both: Docker Compose for application services and Vagrant for infrastructure testing (e.g., testing Ansible playbooks against a real Ubuntu VM before deploying to production servers).

Share this tool: X / Twitter LinkedIn
✓ 60,000+ developers use DevPlaybook ★★★★★ 4.8 / 5 on Gumroad ✓ MIT licensed · Instant download ✓ No login required

Related Products

on Gumroad

You Might Also Need

More Free Tools

Enjoying this tool? Get more like it.

Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.

DevPlaybook Pro 7 days free

Unlock AI-Powered Dev Tools

  • ⚡ AI Code Review, Doc Generator & SQL Builder
  • ⚡ All premium templates & early access
  • ⚡ Member discounts on Gumroad products
Start Free Trial →

$9/mo after trial · Cancel anytime

Want the full toolkit?

Get DevPlaybook Pro

Every template, guide, boilerplate, and automation script in one bundle. 13 premium products — grab them all at once and save big.

$79
$241 separately Save $162 (67% off)
Get DevPlaybook Pro — $79 →

MIT licensed · Instant download · No subscription

See what's included → Browse all deals →