Docker containers vs VMs for quick consistent local dev

Here’s a well-guarded secret that most developers, teams, and agencies don’t share with their clients: a ton of work is needed just to get to the work. Have you ever lost hours to managing your team’s local development environments? Maybe you’ve enjoyed a few too many coffee breaks while waiting for your virtual machines to spin up and now you’re spinning, too? Perhaps you’re just overwhelmed with the options available—and who could blame you with all these local dev environments just for Drupal development (that’s right, 37 at the time of writing!)? Not to worry, we’ve got you covered: In this post, we’ll review four different daily developer goals and how you might reach them using a Virtual Machine (VM), Docker, and DDEV to show the improvements at each level.

Back in the day, one LAMP stack on one computer was what we worked with, plain and simple. Now we’re running on a constellation of services and software both locally and in our live environments. Not only can it be a handful to track and manage all of these, but it’s become increasingly complex to maintain consistency across local, development, staging, and production environments for all team members across all projects.

Two of the current top solutions to this onslaught of complexity are virtual machines (VMs) and containers (with Docker being by far the most popular container solution out there currently.) Compared with VMs, Docker containers are a better solution for local development workflows for several reasons. After a brief outline comparing what VMs and containers are, we’ll compare and contrast them in terms of quick and consistent setup, accelerated dev-to-deploy workflows, and improved team collaboration.

About VMs

A virtual machine (VM) is virtualized hardware running a guest operating system on top of your local operating system (OS), with services managed by a “hypervisor” such as VirtualBox—essentially a computer within your computer. Other tools such as Vagrant, Chef, Puppet, and Ansible can help make VMs portable, reproducible, and automatable for sharing among teams.

One of the advantages of using a VM is that your app is highly isolated and consolidated, allowing for unique configurations for each project. One disadvantage of using a VM is that they are resource intensive: it needs its own full AMP stack, plus a full OS, as well as all other virtualized hardware like CPU, memory, and network interfaces. VMs can also take 10 minutes or more to provision and build if you’re starting from scratch, depending on your hardware and the number of packages you’re installing.

About containers

Docker allows applications to be isolated into containers with configuration files stating exactly what dependencies they need to run, which can be easily distributed from one machine to the next. Sounds a lot like VMs, right? Isolated environments, portable, reproducible. Let’s take a closer look.

Containers run as isolated spaces within your operating system with predefined apps and services running inside. Unlike VMs, they take advantage of the systems your OS offers and share memory as needed, when running. This makes containers faster to set up and run than full OS stack VMs and significantly less memory intensive. If your hardware can run Docker either natively or through Docker Community Editions or Docker Toolbox, you’re good to go on up-to-date versions of Linux, Windows, and MacOS. Since containers depend on the Linux kernel to run, Docker for Mac and Docker for Windows each use native OS hypervisors with a slim Alpine Linux VM to run the containers themselves.

Docker is a container engine; it does for containers what Vagrant does for VMs. Docker manages and streamlines the interactions between your app, services, and environment. It also acts as the resource manager for the containers as the hypervisor does for VMs. Docker usage really took off after it added native virtualization support for Mac and Windows in 2016, since then, Google Trends data suggest it has become a best-practice tool of choice for web development.

Google trends – Docker v VMs 2015-2018

Containers need only seconds to spin up: “I needed something I can get up quick. Instead of sticking Vagrant up and going to make a cup of tea, then coming back and it almost being finished. Vagrant was the go-to, and then Docker came out, and everyone started moving to Docker.”

Alex Burrows, “DDEV: It does what it says on the tin”

Quick and consistent setup

Your goals: Install a local development environment for your project quickly and easily. Avoid hunting down dependencies or troubleshooting issues only to find that the next build opens up a whole different can of worms.

With VMs

Ideally, “Getting a project up and running locally should be something ‘quick and easy.’ Pull the code, start the stack, maybe grab a DB dump and files, import. Done.” – Leonid Makarov presenting on VM alternatives at DrupalCon Baltimore.

Onboarding with VMs can be time-consuming. Provisioning and upkeep for a VM can also take a lot of effort, especially if you’re not using a tool like Vagrant. The VM or Vagrant boxes can take a long time to build or fail to build entirely, and your developers are increasingly distracted by troubleshooting their local environment. Even in best-case scenarios for Drupal development environments, VMs are the slowest option for getting a local environment set up at 8 min 33 sec simply due waiting on the installation and configuration of the full stack and VM.

Tools like Varying Vagrant Vagrants (VVV) for WordPress development use Vagrant with VirtualBox to spin up a new VM: Check the requirements, git clone the repo, copy the config file over and `vagrant up`, then visit the dashboard to see your site. The VVV VM with the OS is about 332MB plus 100 MB of packages—not too bad on a fast connection. You can then add site templates and scripts to automate the build process for your specific project. While there are tools like Drupal VM with Ansible and Vagrant that make spinning up with a VM for local development as easy as possible, there can still be hiccups in the build process.

As Adam Bergstein said in our previous post, “It would take upwards of 20-30 mins to provision a [virtual] machine. And then if it wasn’t provisioned right, or if there was configuration missed, I would have to go back and do that. I would destroy it, and rebuild it.” He said it could take anywhere from 2-3 iterations. “And that’s massively disruptive.”

With Docker

Docker environments are lightweight and fast to start thanks to an automated build process dictated by a Dockerfile. Your app and dependencies are pre-compiled and pre-installed rather than needing to install and configure the full AMP stack and OS inside a VM. These Docker images can be layered so that updates require incremental downloads versus full VM downloads. You can be up-and-running in a couple of minutes.

But if you want to configure and maintain your own custom Dockerized local development solution you’ll also be facing a steep learning curve. You’ll be learning how to write a Dockerfile to define your environment, plus a Docker Compose YAML file to define your environment’s services and containers. This is pretty powerful stuff and definitely worth taking a look at if that adds value to your role and expertise. But if a deep understanding of containerization is not in your job description …

DDEV to the rescue!

Our own Docker-based local development environment solution is DDEV-Local. We get the complexity of configuring your own Docker setup out of your way so you only need to plug and play with your project. If you want to take a peek at the inner workings, check out our documentation on extending DDEV: “DDEV uses Docker Compose to define and run the multiple containers that make up the local environment for a project. Docker Compose supports defining multiple compose files to facilitate sharing Compose configurations between files and projects, and DDEV is designed to leverage this ability.”

DDEV is an open source development tool with an Apache 2.0 license and plenty of flexibility to configure, extended, and customize for your current project. Use one of our quick start guides to really speed up launching a fresh install of TYPO3 CMS, WordPress, Drupal, or Backdrop CMS!

Tip: Check out this tutorial on how to set up a mac PHP development environment. The video shows how to install Docker on macOS.

Accelerated Dev-to-Deploy Workflows

Your goals: Local development for Drupal, WordPress, and other CMSs, needs to be fast, easy to use, and provide environmental parity. Spend less time tracking down problems stemming from inconsistent local development environments and more time delivering code.

With VMs

When you set up a VM, you partition a fixed amount of disk and memory space for it, whether it’s the correct amount or not, leading you into a Goldilocks situation: Is your VM too big, too small or just right? Virtualizing at the hardware level means massive resource footprints for each application, running redundant operating systems on top of the hypervisor. To put it simply, if you’re running 20 VMs you’re also booting 20 operating systems. Plus the minimum resources for each container. Plus the hypervisor. That is an incredible load for your machine to handle even before you even start really working.

Once the OS is running in a VM there’s not always enough space left for the actual workload. Each VM you build and run will continue to eat up your resources, including memory, CPU and battery life while it runs. You can shut down your VM to ease the load, or destroy it completely to conserve disk space if you don’t mind rebuilding it. Each build, rebuild, boot, debugging, troubleshooting and re-configuring adds all kinds of costs to your workflow when you could be staring down code problems instead.

In terms of security and failures, your VM environments are all unique and isolated. If the OS on one VM fails, others on the same host will continue to run. Users inside a VM do not have access to other VMs or the host and it’s very difficult for code to escape and cause harm elsewhere (though not impossible).

With Docker

VMs gave you a box that looked tidy on the outside, but inside you had more boxes, some half empty, others overflowing. Docker containers organize your services a bit like a Tetris game—each service is shrink wrapped and neatly stacked on your machine. If you “Tetris together” all the smaller microservices blocks of containers, you’ll have a lot more space left over (and a much higher score). Alternatively, you’re following the Marie Kondo method of organizing your drawers: accessible, neatly folded items streamline the functionality of the container/drawer.

With Docker, you’ll have one OS running and Docker-managed resources for all of your containers. Automated scripts can rebuild the exact same stack when an instance fails because containers are stored and versioned. If you need a bit more space, you can backup your database, stop and destroy your containers. Just don’t forget that first step.

Containers are not “secure” boxes in the way that VMs are, and require a well-maintained stack of components from host machine to tools to Docker. While your security posture may be more complex with containers it is also more adaptable and resilient because containers enable agile best-practices.


“Docker doesn’t solve the scripting and container setup for you—so if you decide to use Docker, be prepared to maintain that tooling and infrastructure” – Local Drupal Development Roundup, Andrew Berry

Or offload that complexity onto us: DDEV-Local is our tool that helps developers speed up and improve their Docker workflows. We take care of scripts, project set-up, best practices, updates, you’ll just complete the initial tool setup, cd into your project’s directory and run `ddev start`.

Stopping a Docker container saves memory and CPU usage and containers can be removed as soon as you’ve backed up your database. DDEV makes this nondestructive by saving your database outside of Docker so you can run `ddev remove` and preserve your data.

Improved team collaboration

Your goals: Make it easier to solve problems together, quickly. You want to be able to ship your project to all your devs or be able to spin it up and examine the work on that upcoming call …  even when they’re running everything from OSX to Fedora Linux to Windows 10 Pro.

With VMs

Someone will need to provision and configure your VM to work with your project and your production server. Once that’s done, deploying to team members should be straightforward, but may also introduce disparities when working with different host operating systems.

VMs also introduce inconsistency when the production environment is a fleet of VMs but the local development environment is one VM. Any stage where environments differ has the potential to throw a wrench in the works, like moving from a local file system to GlusterFS or Valhalla on Pantheon.

If you add Vagrant to your toolset it becomes easier to deploy consistent development environments to your team. However, download, build, and boot times of 8 to 30 minutes or more put a definite constraint on your team’s continuous integration and continuous deployment workflow.

With Docker

Docker provides a packaging and deployment model and infrastructure for publishing highly portable lightweight containers. With lots of microservices, it will be much faster to start a Docker package on each team member’s machine than to wait for VMs to build and provision.

“Whereas it might take you 5 minutes to get a VM up and running to start your work, with Docker (and especially DDEV) you can start from zero, commit a CSS change, and throw away the containers and move onto the next site before the VM was even up. This is one huge step forward in allowing the developer to get into and stay in a state of flow rather than getting constantly stopped by their tools.”

Rick Manelius

You can add complex requirements for microservices in a Dockerfile (or read on below for an even easier solution), move to testing with the exact same environment, tear down the entire environment when you’re done to conserve resources, and finally deploy, knowing your local environment is a duplicate of the environment on your live server.


DDEV-Local gives you matching environments, quick deployments, and cross-platform parity between team members and your production server. Your tools are configured, nothing needs to boot, and you can get new developers or contributors up and running in minutes. A VM has to be set up apart from the project codebase. With Docker and DDEV, you can commit the exact container image pointers in your codebase, taking the guesswork out of what is needed and allowing new users to just spin up without thinking. Working with the exact same tools makes it so much easier to solve problems together.

Get started integrating DDEV with your existing project by checking out our documentation on importing your database and files here. You don’t need to re-configure anything to get up and running, just tell DDEV-Local a few things about your project like its name and docroot location when it asks you via command line prompts.

Conclusion: Why use Docker containers instead of VMs?

When compared to virtual machines, Docker containers are a leap forward in performance and resource efficiency but can be complex to configure and manage. We’ve built DDEV to simplify and streamline your team’s workflow by getting the complexities of set-up and collaboration out of your way. DDEV is a robust and reliable, out-of-the-box, dev-to-deploy solution to support your team and the way you already work.

Are you using a VM for your local dev environment? We’d love to hear what you think – chat with us on Twitter.

Photo by Mauro Licul on Unsplash

Share this post: