Mastering Docker Volumes: Named vs. Anonymous & When to Use Each

Using Unnamed Volumes in Docker-Compose

Before diving into named volumes, let’s first see how an unnamed volume is created.

version: "3.6"
services:
  web:
    build: ./server/
    volumes:
      - ./server:/app
      - ./server/node_modules:/app/node_modules
    ports:
      - "4000:4000"
    depends_on:
      - postgres
    environment:
      - NODE_ENV=development

  postgres:
    image: postgres:11
    restart: always
    ports:
      - "5432:5432"
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: postgres

Explanation

  • ./server:/app maps the /app directory inside the container to the ./server directory on your host machine.
  • ./server/node_modules:/app/node_modules ensures that dependencies are kept in sync.

However, unnamed volumes can become difficult to manage, especially when working with multiple projects.

Why You Should Use Named Volumes

If you're handling multiple projects with Docker, your volumes can quickly become a mess:

docker volume ls
DRIVER    VOLUME NAME
local     2f075f6a07ebb...
local     reddit-clone_db_data
local     reddit-clone_server
local     postgres_db_vol

Named volumes make it easier to manage and delete specific volumes:

# With named volumes:
docker volume rm reddit-clone_server_node_modules

# Instead of trying to guess:
docker volume rm 2f075f6a07ebb...

Using Named Volumes in Docker-Compose

version: "3.6"
services:
  postgres:
    image: postgres:11
    restart: always
    ports:
      - "5432:5432"
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: postgres

volumes:
  db_data:

In this case, /var/lib/postgresql/data is mapped to a named volume db_data.

Mapping a Named Volume to a Specific Filesystem Path

For development, you may want to bind the named volume to a specific directory on your host machine:

version: "3.6"
services:
  web:
    build: ./server/
    volumes:
      - server:/app
      - server_node_modules:/app/node_modules
    ports:
      - "4000:4000"
    depends_on:
      - postgres
    environment:
      - NODE_ENV=development

  postgres:
    image: postgres:11
    restart: always
    ports:
      - "5432:5432"
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: postgres

volumes:
  db_data:
  server:
    driver_opts:
      type: none
      device: ${PWD}/server
      o: bind
  server_node_modules:
    driver_opts:
      type: none
      device: ${PWD}/server/node_modules
      o: bind

Caveat: Named Volumes Are Not Auto-Deleted

Unlike anonymous volumes, named volumes persist even after running docker-compose rm -v. You must delete them manually:

docker volume rm <volume_name>

When to Use Anonymous Volumes

node_modules Issues

Mapping node_modules from the host can cause problems:

  • If the host system and Docker image use different OS versions, dependencies may break.
  • The container’s node_modules can get hidden if the host directory is empty.

Using an anonymous volume can help:

services:
  server:
    build: ./server/
    volumes:
      - server:/app
      - ./server/node_modules:/app/node_modules
volumes:
  server:
    driver_opts:
      type: none
      device: ${PWD}/server
      o: bind

This ensures node_modules persists inside the container without interference from the host.

Conclusion

Named volumes provide better organization and persistence, but anonymous volumes can be useful in some scenarios like handling node_modules. Understanding when to use each can help you avoid common pitfalls in Docker development.