Docker Compose allows you to configure volumes and bind mounts using a short syntax. A few examples:
Which of these are volumes and which are a bind mounts?
Whenever I had to read a
docker-compose.yml file, I had to look up the official documentation or run a quick local experiment to figure out how Docker Compose would mount the directories into the container.
I wrote this article so that next time you read a Docker Compose file, you won’t have to guess anymore. You’ll simply know by looking at the syntax whether a volume or a bind mount is used behind the scenes.
The different variations are essentially three unique forms. I list and explain them in this article below.
volumes keys in docker-compose.yml
Before we talk about the different ways to specify volumes, let’s first clarify which
volumes key we’re referring to. In
volumes key can appear in two different places.
version: "3.7" services: database: # ... volumes: # Nested key. Configures volumes for a particular service. volumes: # Top-level key. Declares volumes which can be referenced from multiple services. # ...
In this article, we’ll talk about the nested
volumes key. That’s where you configure volumes for a specific service/container such as a database or web server. This configuration has a short (and a long) syntax format.
Short syntax format and its variations
The volume configuration has a short syntax format that is defined as:
SOURCE can be a named volume or a (relative or absolute) path on the host system. TARGET is an absolute path in the container. MODE is a mount option which can be read-only or read-write. Brackets mean the argument is optional.
This optionality leads to three unique variations you can use to configure a container’s volumes. Docker Compose is smart about recognising which variety is used and whether to use a volume or bind mount.
- No SOURCE – eg.
When only a target is specified, without a source, Docker Compose will create an anonymous directory and mount it as a volume to the target path inside the container.
The directory’s path on the host system is by default
<uuid> is a random ID assigned to the volume as its name.
- A non-path SOURCE – eg.
If a source is present and it’s not a path, then Docker Compose assumes you’re referring to a named volume. This volume needs to be declared in the same file in the top-level
volumes key declaration.
volumes key always declares volumes, never bind mounts. Bind mounts don’t have a name and they can’t be named.
- A path SOURCE – eg.
If source is a path, absolute or relative, Docker Compose will bind mount the folder into the container. Relative paths starting with
.. are relative to the location of
Bind mounts are discouraged for database containers since that makes them less portable. Bind mounts are specific to the host system and Docker doesn’t manage them. The official docs have a section about volumes vs bind mounts that explains the differences between the two in more detail.
Summing it up
Docker Compose allows you to configure volumes by using a short syntax string. Whether you end up with a volume or a bind mount, depends on which short syntax variation you use.
When you don’t specify a source, Docker Compose will create an anonymous volume. If source is not a path, Docker Compose will assume source is a named volume. Sources that are relative or absolute paths are bind-mounted into the container.
If you liked this type of article that uncovers a primary feature, you might find my article about the EXPOSE instruction in Dockerfile interesting. I clarify a few misconceptions around exposing a port and explain what EXPOSE does, and doesn’t do.