Introduction
When working with Docker containers, understanding how to properly manage data persistence is crucial. Docker provides three main approaches for mounting data into containers: Volumes, Bind Mounts, and tmpfs mounts. Each has distinct characteristics, use cases, and trade-offs.
This comprehensive guide explores all Docker mount types, their differences, practical examples, and best practices to help you choose the right approach for your specific needs.
What is Mounting in Docker?
Mounting in Docker refers to the process of making host filesystem directories or Docker-managed storage available inside containers. This allows containers to:
- Access host files and directories
- Persist data beyond container lifecycle
- Share data between multiple containers
- Exchange configuration files, logs, and application code
graph TD
A[Docker Mount Types] --> B[Volumes]
A --> C[Bind Mounts]
A --> D[tmpfs Mounts]
B --> B1[Docker-managed storage]
B --> B2[/var/lib/docker/volumes]
B --> B3[Production data persistence]
C --> C1[Direct host path mapping]
C --> C2[Development & code sync]
C --> C3[Configuration files]
D --> D1[In-memory storage]
D --> D2[Temporary data]
D --> D3[Sensitive information]
style B fill:#4ecdc4
style C fill:#feca57
style D fill:#ff6b6b
Three Types of Docker Mounts
Quick Comparison Table
| Feature | Docker Volume | Bind Mount | tmpfs Mount |
|---|---|---|---|
| Management | Docker-managed | User-managed | Docker-managed |
| Storage Location | /var/lib/docker/volumes | Anywhere on host | Memory (RAM) |
| Portability | High | Low | N/A |
| Performance | Good | Good | Excellent |
| Persistence | Yes | Yes | No (volatile) |
| Best For | Production data | Development | Temporary data |
| Can Share Between Containers | Yes | Yes | No |
| Backup/Migration | Easy | Manual | N/A |
| Host Path Dependency | No | Yes | No |
1. Docker Volumes (Recommended for Production)
What Are Docker Volumes?
Docker Volumes are the preferred mechanism for persisting data. They are completely managed by Docker and stored in a dedicated location on the host.
graph LR
subgraph "Host System"
V[/var/lib/docker/volumes]
V1[my-vol/]
V2[db-data/]
V --> V1
V --> V2
end
subgraph "Container 1"
C1[/app/data]
end
subgraph "Container 2"
C2[/var/lib/mysql]
end
V1 --> C1
V2 --> C2
style V fill:#4ecdc4
style V1 fill:#a8e6cf
style V2 fill:#a8e6cf
Characteristics
- Managed by Docker: Docker handles all lifecycle operations
- Named or Anonymous: Can be explicitly named or auto-generated
- Shared Access: Multiple containers can mount the same volume
- Volume Drivers: Support for cloud storage, network storage, etc.
- Isolated from Host: No direct dependency on host directory structure
Basic Volume Commands
1# Create a named volume
2docker volume create my-volume
3
4# List all volumes
5docker volume ls
6
7# Inspect volume details
8docker volume inspect my-volume
9
10# Remove a volume
11docker volume rm my-volume
12
13# Remove all unused volumes
14docker volume prune
Using Volumes in Containers
1. Short Syntax (-v flag)
1# Named volume
2docker run -v my-volume:/app/data nginx:latest
3
4# Anonymous volume (auto-generated name)
5docker run -v /app/data nginx:latest
6
7# Multiple volumes
8docker run \
9 -v db-data:/var/lib/mysql \
10 -v config-data:/etc/mysql/conf.d \
11 mysql:8.0
2. Long Syntax (–mount flag) - Recommended
1docker run \
2 --mount type=volume,source=my-volume,target=/app/data \
3 nginx:latest
4
5# With additional options
6docker run \
7 --mount type=volume,source=my-volume,target=/app/data,readonly \
8 nginx:latest
Docker Compose Example
1services:
2 app:
3 image: node:18
4 volumes:
5 # Named volume
6 - app-data:/app/data
7 - app-logs:/app/logs
8 environment:
9 - NODE_ENV=production
10
11 database:
12 image: postgres:15
13 volumes:
14 # Named volume for database persistence
15 - postgres-data:/var/lib/postgresql/data
16 # Named volume for initialization scripts
17 - postgres-init:/docker-entrypoint-initdb.d
18 environment:
19 - POSTGRES_PASSWORD=secret
20
21# Volume definitions
22volumes:
23 app-data:
24 driver: local
25 app-logs:
26 driver: local
27 postgres-data:
28 driver: local
29 postgres-init:
30 driver: local
Advanced Volume Features
1. Volume Drivers
1# Use NFS volume driver
2docker volume create \
3 --driver local \
4 --opt type=nfs \
5 --opt o=addr=192.168.1.100,rw \
6 --opt device=:/path/to/dir \
7 nfs-volume
8
9# Use AWS EFS driver (requires plugin)
10docker volume create \
11 --driver rexray/efs \
12 --name efs-volume
13
14# Azure File Storage
15docker volume create \
16 --driver azure_file \
17 --name azure-volume \
18 -o share=myshare
2. Volume with Specific Permissions
1# Create volume with specific user/group
2docker volume create \
3 --opt type=tmpfs \
4 --opt device=tmpfs \
5 --opt o=uid=1000,gid=1000 \
6 my-volume
3. Read-Only Volumes
1# Mount volume as read-only
2docker run \
3 -v my-volume:/app/data:ro \
4 nginx:latest
5
6# Or with --mount
7docker run \
8 --mount type=volume,source=my-volume,target=/app/data,readonly \
9 nginx:latest
Pros and Cons
Pros
- Easy to backup and migrate: Can be backed up using
docker cpor volume plugins - Cross-platform: Works on Linux, Windows, and macOS
- Managed lifecycle: Docker handles creation and cleanup
- Better performance on Docker Desktop: Optimized for macOS and Windows
- Volume drivers: Can store volumes on remote hosts or cloud providers
- Safe sharing: Multiple containers can safely share volumes
- Pre-populated content: New volumes can be pre-filled from container content
Cons
- Less direct access: Cannot directly edit files from host without container
- Abstracted location: Files stored in Docker-managed directory
- Requires Docker commands: Need Docker CLI to manage volumes
Use Cases
Database Storage
- PostgreSQL, MySQL, MongoDB data directories
- Ensures data survives container recreation
Application State
- User uploads
- Application-generated files
- Cache directories
Shared Configuration
- Shared config between microservices
- Centralized logging
Backup and Restore Scenarios
1# Backup volume 2docker run --rm \ 3 -v my-volume:/data \ 4 -v $(pwd):/backup \ 5 busybox tar czf /backup/backup.tar.gz /data 6 7# Restore volume 8docker run --rm \ 9 -v my-volume:/data \ 10 -v $(pwd):/backup \ 11 busybox tar xzf /backup/backup.tar.gz -C /
2. Bind Mounts (Best for Development)
What Are Bind Mounts?
Bind Mounts directly map a host directory or file to a container path. The host path must exist before creating the container.
graph LR
subgraph "Host System"
H1[/home/user/project]
H2[/home/user/logs]
H3[/etc/config]
end
subgraph "Container"
C1[/app]
C2[/app/logs]
C3[/etc/app/config]
end
H1 -->|Bind Mount| C1
H2 -->|Bind Mount| C2
H3 -->|Bind Mount| C3
style H1 fill:#feca57
style H2 fill:#feca57
style H3 fill:#feca57
Characteristics
- Direct Host Mapping: Container accesses files directly from host
- Path Dependency: Requires specific host directory structure
- Two-Way Sync: Changes reflect immediately in both directions
- No Docker Management: Docker doesn’t manage the host directory
- Full Host Access: Container has same permissions as mounted directory
Using Bind Mounts
1. Short Syntax (-v flag)
1# Basic bind mount
2docker run -v /host/path:/container/path nginx:latest
3
4# With read-only flag
5docker run -v /host/path:/container/path:ro nginx:latest
6
7# Current directory
8docker run -v $(pwd):/app node:18
9
10# Multiple bind mounts
11docker run \
12 -v $(pwd)/src:/app/src \
13 -v $(pwd)/logs:/app/logs \
14 -v $(pwd)/config.json:/app/config.json \
15 node:18
2. Long Syntax (–mount flag) - More Explicit
1# Basic bind mount
2docker run \
3 --mount type=bind,source=/host/path,target=/container/path \
4 nginx:latest
5
6# Read-only bind mount
7docker run \
8 --mount type=bind,source=/host/path,target=/container/path,readonly \
9 nginx:latest
10
11# With consistency options (macOS/Windows)
12docker run \
13 --mount type=bind,source=$(pwd),target=/app,consistency=cached \
14 node:18
Docker Compose Example
1services:
2 web:
3 image: nginx:latest
4 ports:
5 - "8080:80"
6 volumes:
7 # Bind mount for development - hot reload
8 - ./src:/usr/share/nginx/html
9 - ./nginx.conf:/etc/nginx/nginx.conf:ro
10 - ./logs:/var/log/nginx
11 environment:
12 - ENVIRONMENT=development
13
14 app:
15 image: node:18
16 working_dir: /app
17 volumes:
18 # Sync entire project directory
19 - ./app:/app
20 # But exclude node_modules (use anonymous volume)
21 - /app/node_modules
22 # Mount specific config file
23 - ./app/config/development.json:/app/config/config.json
24 command: npm run dev
25 ports:
26 - "3000:3000"
Development Workflow Example
1# Complete development setup with hot reload
2
3# 1. Project structure
4# project/
5# ├── src/
6# │ ├── index.js
7# │ └── utils/
8# ├── tests/
9# ├── config/
10# └── docker-compose.yml
11
12# 2. Docker Compose configuration
13services:
14 dev:
15 image: node:18
16 working_dir: /app
17 volumes:
18 # Mount source code for hot reload
19 - ./src:/app/src
20 - ./tests:/app/tests
21 - ./package.json:/app/package.json
22 # Use anonymous volume for node_modules
23 - /app/node_modules
24 command: npm run dev
25 ports:
26 - "3000:3000"
27 environment:
28 - NODE_ENV=development
29 - CHOKIDAR_USEPOLLING=true # For file watching
30
31# 3. Start development
32docker compose up
33
34# Now changes to ./src/* are immediately reflected in container!
Advanced Bind Mount Features
1. Consistency Modes (macOS/Windows)
Note (2026): Current Docker Desktop uses VirtioFS file sharing by default and ignores the
cached/delegated/consistentflags; they are accepted only for backward compatibility. For faster bind mounts on macOS/Windows, use VirtioFS (default), Docker Desktop’s synchronized file shares, or keep heavy directories such asnode_modulesin a named volume.
1# Cached: prioritize container performance
2docker run \
3 --mount type=bind,source=$(pwd),target=/app,consistency=cached \
4 node:18
5
6# Delegated: prioritize host performance
7docker run \
8 --mount type=bind,source=$(pwd),target=/app,consistency=delegated \
9 node:18
10
11# Consistent: perfect sync (default, slowest)
12docker run \
13 --mount type=bind,source=$(pwd),target=/app,consistency=consistent \
14 node:18
2. Bind Propagation
1# Shared propagation (default)
2docker run \
3 --mount type=bind,source=/host/path,target=/container/path,bind-propagation=shared \
4 ubuntu
5
6# Private propagation
7docker run \
8 --mount type=bind,source=/host/path,target=/container/path,bind-propagation=private \
9 ubuntu
10
11# Slave propagation
12docker run \
13 --mount type=bind,source=/host/path,target=/container/path,bind-propagation=slave \
14 ubuntu
3. SELinux Labels (Linux)
1# With SELinux label
2docker run -v /host/path:/container/path:z nginx:latest # Private label
3docker run -v /host/path:/container/path:Z nginx:latest # Shared label
Pros and Cons
Pros
- Direct file editing: Edit files on host with any editor
- Real-time sync: Changes immediately reflected in container
- No Docker commands needed: Use normal file operations
- Perfect for development: Hot reload, live debugging
- Share configuration: Easy to share config files
- Specific file mounting: Can mount individual files
Cons
- Host path dependency: Requires specific directory structure
- Less portable: Paths differ across environments
- Security concerns: Container can modify host files
- Permission issues: User ID mismatches can cause problems
- Performance on macOS/Windows: Slower than volumes
- Backup complexity: Must backup host directory separately
Use Cases
Development Environment
1# Hot reload for web development 2docker run \ 3 -v $(pwd)/src:/app/src \ 4 -v $(pwd)/public:/app/public \ 5 -p 3000:3000 \ 6 node:18 npm run devConfiguration Files
1# Mount specific config files 2docker run \ 3 -v /etc/myapp/config.yml:/app/config.yml:ro \ 4 myapp:latestLog Collection
1# Collect logs to host directory 2docker run \ 3 -v $(pwd)/logs:/var/log/app \ 4 myapp:latestTesting and CI/CD
1# Run tests on current codebase 2docker run \ 3 -v $(pwd):/app \ 4 -w /app \ 5 node:18 npm testDatabase Configuration
1# Custom PostgreSQL config 2docker run \ 3 -v $(pwd)/postgresql.conf:/etc/postgresql/postgresql.conf:ro \ 4 -v postgres-data:/var/lib/postgresql/data \ 5 postgres:15
3. tmpfs Mounts (For Temporary Data)
What Are tmpfs Mounts?
tmpfs mounts store data in the host’s memory (RAM). Data exists only while the container runs and is never written to disk.
graph TD
subgraph "Host System"
RAM[System RAM]
RAM --> TM1[tmpfs Mount 1]
RAM --> TM2[tmpfs Mount 2]
end
subgraph "Container"
C1[/tmp]
C2[/run]
end
TM1 -->|In-Memory| C1
TM2 -->|In-Memory| C2
N[Container Stops] -->|Data Lost| X[❌ Data Deleted]
style RAM fill:#ff6b6b
style TM1 fill:#ffb3ba
style TM2 fill:#ffb3ba
style X fill:#ff6b6b
Characteristics
- Memory Storage: Data stored in RAM, not disk
- Volatile: Data lost when container stops
- Fast Performance: No disk I/O overhead
- Secure: No data leakage to disk
- Linux Only: Not available on Windows containers
- Size Limited: Limited by available memory
Using tmpfs Mounts
1. Short Syntax (–tmpfs flag)
1# Basic tmpfs mount
2docker run --tmpfs /app/tmp nginx:latest
3
4# With size limit (100MB)
5docker run --tmpfs /app/tmp:size=100m nginx:latest
6
7# Multiple tmpfs mounts
8docker run \
9 --tmpfs /tmp \
10 --tmpfs /run:size=64m \
11 ubuntu:latest
2. Long Syntax (–mount flag)
1# Basic tmpfs
2docker run \
3 --mount type=tmpfs,target=/app/tmp \
4 nginx:latest
5
6# With options
7docker run \
8 --mount type=tmpfs,target=/app/tmp,tmpfs-size=100m,tmpfs-mode=1770 \
9 nginx:latest
Docker Compose Example
1services:
2 app:
3 image: myapp:latest
4 tmpfs:
5 # Simple tmpfs mount
6 - /tmp
7 - /run
8
9 web:
10 image: nginx:latest
11 volumes:
12 # Using long syntax for more control
13 - type: tmpfs
14 target: /app/cache
15 tmpfs:
16 size: 100m
17 mode: 1770
18 - type: tmpfs
19 target: /tmp
20 tmpfs:
21 size: 50m
22
23 database:
24 image: postgres:15
25 volumes:
26 # Persistent data on volume
27 - db-data:/var/lib/postgresql/data
28 tmpfs:
29 # Temporary files in memory
30 - /tmp
31 - /run/postgresql:size=100m
32
33volumes:
34 db-data:
Advanced tmpfs Options
1# With all options
2docker run \
3 --mount type=tmpfs,target=/app/tmp,\
4tmpfs-size=100m,\
5tmpfs-mode=1777,\
6tmpfs-uid=1000,\
7tmpfs-gid=1000 \
8 myapp:latest
9
10# Options explained:
11# - tmpfs-size: Maximum size (100MB)
12# - tmpfs-mode: Unix permissions (1777 = sticky bit + rwx)
13# - tmpfs-uid: Owner user ID
14# - tmpfs-gid: Owner group ID
Pros and Cons
Pros
- Excellent performance: In-memory operations are extremely fast
- Secure: Sensitive data never written to disk
- No disk wear: Reduces SSD/HDD wear for temporary files
- Automatic cleanup: Data automatically removed when container stops
- No persistence overhead: No need to manage cleanup
Cons
- Volatile storage: All data lost when container stops
- Linux only: Not supported on Windows containers
- Memory limited: Uses system RAM (limited resource)
- Cannot share: Cannot share tmpfs between containers
- No backup possible: Data cannot be backed up
- Memory pressure: Can affect system performance if overused
Use Cases
Temporary Processing
1# Image processing with temporary files 2docker run \ 3 --tmpfs /tmp:size=1g \ 4 -v $(pwd)/input:/input:ro \ 5 -v $(pwd)/output:/output \ 6 image-processorSensitive Data
1# Handle sensitive credentials in memory 2docker run \ 3 --tmpfs /secrets:size=10m,mode=0700 \ 4 -e SECRET_FILE=/secrets/token \ 5 myapp:latestBuild Cache
1# Fast build with in-memory cache 2docker run \ 3 --tmpfs /tmp:size=2g \ 4 -v $(pwd):/app \ 5 -w /app \ 6 node:18 npm run buildSession Storage
1# Web server with in-memory sessions 2docker run \ 3 --tmpfs /var/lib/nginx/sessions:size=200m \ 4 nginx:latestTesting Environment
1# Fast test execution with tmpfs 2docker run \ 3 --tmpfs /tmp:size=500m \ 4 --tmpfs /var/tmp:size=500m \ 5 -v $(pwd):/app \ 6 test-runner npm test
Complete Comparison Matrix
Feature Comparison
| Feature | Volume | Bind Mount | tmpfs |
|---|---|---|---|
| Storage Location | /var/lib/docker/volumes | Custom host path | Memory (RAM) |
| Managed By | Docker | Host/User | Docker |
| Persistence | Yes (survives container) | Yes (survives container) | No (volatile) |
| Portability | High | Low | Medium |
| Performance (Linux) | Good | Good | Excellent |
| Performance (macOS/Win) | Excellent | Moderate | Excellent |
| Host Access | Indirect | Direct | None |
| Sharing Between Containers | Yes | Yes | No |
| Backup/Restore | Easy | Manual | Not applicable |
| Size Limit | Host disk | Host disk | RAM |
| Platform Support | All | All | Linux only |
| SELinux/AppArmor | Handled by Docker | Manual configuration | Handled by Docker |
| Initial Content | Can inherit | Uses existing | Empty |
Performance Comparison
graph LR
A[Performance by Platform] --> B[Linux Host]
A --> C[macOS/Windows]
B --> B1[Volume: ★★★★☆]
B --> B2[Bind Mount: ★★★★☆]
B --> B3[tmpfs: ★★★★★]
C --> C1[Volume: ★★★★★]
C --> C2[Bind Mount: ★★☆☆☆]
C --> C3[tmpfs: ★★★★★]
style B3 fill:#4ecdc4
style C1 fill:#4ecdc4
style C3 fill:#4ecdc4
Use Case Decision Tree
graph TD
A[Choose Mount Type] --> B{Need Persistence?}
B -->|No| C[tmpfs Mount]
B -->|Yes| D{Production or Development?}
D -->|Production| E[Docker Volume]
D -->|Development| F{Need Direct File Access?}
F -->|Yes| G[Bind Mount]
F -->|No| H[Docker Volume]
C --> I[Fast, Secure, Volatile]
E --> J[Managed, Portable, Backupable]
G --> K[Direct Access, Hot Reload]
H --> L[Isolated, Performance]
style E fill:#4ecdc4
style G fill:#feca57
style C fill:#ff6b6b
Best Practices
1. Volume Best Practices
1# Good: Named volumes with clear purpose
2services:
3 db:
4 image: postgres:15
5 volumes:
6 - postgres-data:/var/lib/postgresql/data
7 - postgres-backup:/backup
8
9volumes:
10 postgres-data:
11 name: myapp_postgres_data
12 postgres-backup:
13 name: myapp_postgres_backup
Best Practices:
- Use named volumes instead of anonymous volumes
- Add meaningful volume names
- Regular backup strategy
- Use volume drivers for production
- Document volume contents and purpose
2. Bind Mount Best Practices
1# Good: Clear separation of concerns
2services:
3 dev:
4 image: node:18
5 volumes:
6 # Source code - read/write
7 - ./src:/app/src
8 # Configuration - read-only
9 - ./config/development.json:/app/config/config.json:ro
10 # Logs - write only
11 - ./logs:/app/logs
12 # Exclude node_modules
13 - /app/node_modules
Best Practices:
- Use read-only (
:ro) when possible - Exclude unnecessary directories
- Use absolute paths or
$(pwd) - Document required host directory structure
- Be careful with permissions
- Avoid bind mounts in production
3. tmpfs Best Practices
1# Good: Size limits and appropriate use
2services:
3 app:
4 image: myapp:latest
5 tmpfs:
6 # Limit size to prevent memory exhaustion
7 - /tmp:size=100m,mode=1777
8 - /run:size=50m
9 deploy:
10 resources:
11 limits:
12 memory: 512M # Account for tmpfs in memory limit
Best Practices:
- Always set size limits
- Include tmpfs size in container memory limits
- Use for truly temporary data only
- Monitor memory usage
- Not suitable for large datasets
4. Security Best Practices
1# Read-only root filesystem with writable tmpfs
2docker run \
3 --read-only \
4 --tmpfs /tmp:size=100m \
5 --tmpfs /run:size=50m \
6 myapp:latest
7
8# User namespaces to avoid root access
9docker run \
10 --userns-remap=default \
11 -v my-volume:/app/data \
12 myapp:latest
13
14# Specific user/group
15docker run \
16 --user 1000:1000 \
17 -v my-volume:/app/data \
18 myapp:latest
5. Production Recommendations
1# Production setup example
2services:
3 app:
4 image: myapp:1.2.3
5 volumes:
6 # Named volumes for persistent data
7 - app-data:/var/lib/app
8 - app-logs:/var/log/app
9 # Read-only bind mounts for config
10 - ./config/production.yml:/etc/app/config.yml:ro
11 tmpfs:
12 # In-memory temporary files
13 - /tmp:size=100m
14 deploy:
15 replicas: 3
16 resources:
17 limits:
18 memory: 512M
19
20 db:
21 image: postgres:15
22 volumes:
23 # Volume with backup strategy
24 - postgres-data:/var/lib/postgresql/data
25 environment:
26 - POSTGRES_PASSWORD_FILE=/run/secrets/db_password
27 secrets:
28 - db_password
29 tmpfs:
30 - /tmp:size=50m
31
32volumes:
33 app-data:
34 driver: local
35 driver_opts:
36 type: none
37 o: bind
38 device: /mnt/app-data
39 app-logs:
40 driver: local
41 postgres-data:
42 driver: local
43 driver_opts:
44 type: none
45 o: bind
46 device: /mnt/postgres-data
47
48secrets:
49 db_password:
50 external: true
Real-World Examples
Example 1: Full-Stack Application
1services:
2 # Frontend (Development)
3 frontend:
4 image: node:18
5 working_dir: /app
6 command: npm run dev
7 ports:
8 - "3000:3000"
9 volumes:
10 # Bind mounts for hot reload
11 - ./frontend/src:/app/src
12 - ./frontend/public:/app/public
13 - ./frontend/package.json:/app/package.json
14 # Anonymous volume for node_modules
15 - /app/node_modules
16 tmpfs:
17 # Fast build cache
18 - /app/.cache:size=500m
19 environment:
20 - NODE_ENV=development
21 - CHOKIDAR_USEPOLLING=true
22
23 # Backend (Production-like)
24 backend:
25 image: mybackend:latest
26 ports:
27 - "8080:8080"
28 volumes:
29 # Volume for uploaded files
30 - backend-uploads:/app/uploads
31 # Volume for generated reports
32 - backend-reports:/app/reports
33 # Read-only config
34 - ./backend/config.yml:/app/config.yml:ro
35 tmpfs:
36 # Session storage in memory
37 - /tmp/sessions:size=200m
38 environment:
39 - NODE_ENV=production
40 - LOG_LEVEL=info
41
42 # Database (Production)
43 database:
44 image: postgres:15
45 volumes:
46 # Persistent data storage
47 - postgres-data:/var/lib/postgresql/data
48 # Initialization scripts
49 - ./database/init:/docker-entrypoint-initdb.d:ro
50 tmpfs:
51 # PostgreSQL runtime files
52 - /run/postgresql:size=100m
53 environment:
54 - POSTGRES_PASSWORD=secret
55 - POSTGRES_DB=myapp
56
57 # Cache (Production)
58 redis:
59 image: redis:7-alpine
60 volumes:
61 # Persistent cache data
62 - redis-data:/data
63 # Custom configuration
64 - ./redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
65 command: redis-server /usr/local/etc/redis/redis.conf
66
67 # Nginx (Production)
68 nginx:
69 image: nginx:latest
70 ports:
71 - "80:80"
72 - "443:443"
73 volumes:
74 # Configuration
75 - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
76 - ./nginx/conf.d:/etc/nginx/conf.d:ro
77 # SSL certificates
78 - ./nginx/ssl:/etc/nginx/ssl:ro
79 # Static files
80 - frontend-build:/usr/share/nginx/html:ro
81 # Logs
82 - nginx-logs:/var/log/nginx
83 tmpfs:
84 # Client body temp files
85 - /var/cache/nginx:size=500m
86 depends_on:
87 - frontend
88 - backend
89
90volumes:
91 backend-uploads:
92 backend-reports:
93 postgres-data:
94 redis-data:
95 frontend-build:
96 nginx-logs:
Example 2: Microservices with Shared Volumes
1services:
2 # Service 1: File Processor
3 processor:
4 image: file-processor:latest
5 volumes:
6 # Shared volume for file exchange
7 - shared-files:/app/files
8 # Processed files output
9 - processed-files:/app/output
10 tmpfs:
11 # Fast processing workspace
12 - /tmp/workspace:size=1g
13
14 # Service 2: File Analyzer
15 analyzer:
16 image: file-analyzer:latest
17 volumes:
18 # Read from processed files
19 - processed-files:/app/input:ro
20 # Write analysis results
21 - analysis-results:/app/results
22 tmpfs:
23 # Analysis cache
24 - /tmp/cache:size=500m
25
26 # Service 3: API Server
27 api:
28 image: api-server:latest
29 ports:
30 - "8080:8080"
31 volumes:
32 # Read analysis results
33 - analysis-results:/app/data:ro
34 # API logs
35 - api-logs:/var/log/api
36
37volumes:
38 shared-files:
39 processed-files:
40 analysis-results:
41 api-logs:
Example 3: Development Environment
1services:
2 app:
3 build:
4 context: .
5 dockerfile: Dockerfile.dev
6 command: npm run dev
7 ports:
8 - "3000:3000"
9 volumes:
10 # Full source code mount
11 - .:/app
12 # Exclude specific directories
13 - /app/node_modules
14 - /app/.git
15 - /app/dist
16 tmpfs:
17 # Fast test cache
18 - /app/.cache:size=500m
19 # Jest cache
20 - /tmp/jest:size=200m
21 environment:
22 - NODE_ENV=development
23 - DEBUG=app:*
24
25 db:
26 image: postgres:15
27 ports:
28 - "5432:5432"
29 volumes:
30 # Development database
31 - dev-db-data:/var/lib/postgresql/data
32 # Seed data
33 - ./database/seed.sql:/docker-entrypoint-initdb.d/seed.sql:ro
34 environment:
35 - POSTGRES_PASSWORD=devpassword
36 - POSTGRES_DB=devdb
37
38volumes:
39 dev-db-data:
Troubleshooting
Common Issues and Solutions
1. Permission Denied Errors
1# Problem: Permission denied when writing to volume
2# Solution 1: Match user IDs
3docker run \
4 --user $(id -u):$(id -g) \
5 -v $(pwd):/app \
6 myapp:latest
7
8# Solution 2: Change ownership in Dockerfile
9FROM node:18
10RUN useradd -u 1000 -m appuser
11USER appuser
12
13# Solution 3: Use init container to fix permissions
14docker run \
15 --rm \
16 -v my-volume:/data \
17 alpine:latest \
18 chown -R 1000:1000 /data
2. Data Not Persisting
1# Problem: Data disappears after container restart
2# Wrong: Using container path only
3docker run myapp:latest # No volume specified!
4
5# Correct: Use named volume
6docker run -v my-data:/app/data myapp:latest
3. Bind Mount Not Syncing (macOS/Windows)
1# Problem: File changes not reflected
2# Solution: make sure Docker Desktop uses VirtioFS file sharing (the default);
3# consistency=cached/delegated are ignored on current versions.
4# Or add polling for file watchers
5docker run \
6 -v $(pwd):/app \
7 -e CHOKIDAR_USEPOLLING=true \
8 node:18 npm run dev
4. Volume Taking Too Much Space
1# Check volume sizes
2docker system df -v
3
4# Remove unused volumes
5docker volume prune
6
7# Remove specific volume
8docker volume rm volume-name
9
10# Clean everything (careful!)
11docker system prune -a --volumes
5. Cannot Remove Volume
1# Problem: "volume is in use"
2# Solution 1: Find and stop containers using it
3docker ps -a --filter volume=my-volume
4
5# Solution 2: Force remove container and volume
6docker rm -f container-name
7docker volume rm my-volume
8
9# Solution 3: Remove all stopped containers first
10docker container prune
11docker volume rm my-volume
Migration Strategies
Migrating from Bind Mounts to Volumes
1# Step 1: Create volume
2docker volume create my-app-data
3
4# Step 2: Copy data from bind mount to volume
5docker run --rm \
6 -v /host/path:/source:ro \
7 -v my-app-data:/dest \
8 alpine:latest \
9 sh -c "cp -av /source/. /dest/"
10
11# Step 3: Update docker-compose.yml
12# Before:
13volumes:
14 - /host/path:/app/data
15
16# After:
17volumes:
18 - my-app-data:/app/data
Backing Up and Restoring Volumes
1# Backup volume to tar file
2docker run --rm \
3 -v my-volume:/source:ro \
4 -v $(pwd):/backup \
5 alpine:latest \
6 tar czf /backup/my-volume-backup-$(date +%Y%m%d).tar.gz -C /source .
7
8# Restore volume from tar file
9docker run --rm \
10 -v my-volume:/dest \
11 -v $(pwd):/backup:ro \
12 alpine:latest \
13 tar xzf /backup/my-volume-backup-20250101.tar.gz -C /dest
14
15# Or use dedicated backup tool
16docker run --rm \
17 -v my-volume:/volume \
18 -v $(pwd):/backup \
19 loomchild/volume-backup backup my-volume
Performance Optimization
1. Volume Performance Tips
1# Use local driver with optimal options
2volumes:
3 fast-volume:
4 driver: local
5 driver_opts:
6 type: none
7 o: bind
8 device: /mnt/fast-ssd/data # Use SSD storage
9
10# For databases, use direct mount
11volumes:
12 postgres-data:
13 driver: local
14 driver_opts:
15 type: none
16 o: bind
17 device: /mnt/database-ssd
2. Bind Mount Performance (macOS/Windows)
1# :delegated / :cached are ignored by current Docker Desktop (VirtioFS).
2# The real win is keeping node_modules out of the bind mount:
3services:
4 app:
5 volumes:
6 - ./src:/app/src
7 - node_modules:/app/node_modules # named volume, not a bind mount
8
9volumes:
10 node_modules:
3. tmpfs for Performance-Critical Operations
1# Use tmpfs for build artifacts
2services:
3 builder:
4 volumes:
5 - ./src:/app/src:ro
6 tmpfs:
7 - /app/dist:size=2g
8 - /tmp:size=1g
Conclusion
Choosing the right Docker mount type is crucial for application performance, development workflow, and data management:
Quick Selection Guide
Use Docker Volumes when:
- Building production applications
- Need data persistence across container lifecycles
- Want Docker-managed storage
- Require easy backup and migration
- Need to share data between multiple containers
Use Bind Mounts when:
- Developing applications locally
- Need real-time file synchronization
- Want to edit files directly on host
- Mounting configuration files
- CI/CD pipelines needing access to build artifacts
Use tmpfs Mounts when:
- Handling sensitive temporary data
- Need maximum performance
- Working with temporary build artifacts
- Storing session data
- Processing files that don’t need persistence
Key Takeaways
- Volumes are preferred for production - Docker-managed, portable, and easy to backup
- Bind mounts excel in development - Direct access, hot reload, familiar workflow
- tmpfs provides security and speed - Perfect for temporary, sensitive data
- Mix approaches when appropriate - Different needs require different solutions
- Consider platform differences - Performance varies between Linux, macOS, and Windows
Understanding these mount types and their trade-offs enables you to build more efficient, maintainable, and production-ready containerized applications.
