The 'Volume declared as external, but could not be found' error occurs when Docker Compose cannot locate a volume marked as external. External volumes must exist before running docker-compose and are typically created with `docker volume create`. This is resolved by either creating the volume first or removing the external flag to let Compose manage the volume automatically.
The "Volume declared as external, but could not be found" error indicates that your `docker-compose.yml` file references a Docker volume with `external: true`, but that volume doesn't exist on your system. When you mark a volume as `external` in Docker Compose, you're telling Compose that the volume's lifecycle is managed outside of the application. This means: 1. Docker Compose will NOT create the volume automatically 2. Docker Compose will NOT delete the volume when you run `docker-compose down -v` 3. The volume must already exist before you run `docker-compose up` This is useful when you want to: - Share a volume between multiple Docker Compose projects - Persist data independently of your application's lifecycle - Use volumes created by other tools or processes The error occurs because Compose validates that all external volumes exist before starting any containers. This is a safety feature to prevent containers from starting with missing data dependencies.
The most straightforward fix is to create the volume that Docker Compose is looking for:
# Create a named volume
docker volume create myvolume
# Verify it was created
docker volume ls | grep myvolume
# Inspect the volume details
docker volume inspect myvolumeReplace myvolume with the actual volume name from the error message.
If you need to create a volume with specific options:
# Create with a specific driver
docker volume create --driver local myvolume
# Create with driver options (e.g., for NFS)
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/path/to/share \
nfs-volumeIf you don't need the volume to be external (i.e., you want Compose to manage its lifecycle), remove or modify the external setting:
Before:
volumes:
myvolume:
external: trueAfter (Compose creates and manages the volume):
volumes:
myvolume:Or explicitly set external to false:
volumes:
myvolume:
external: falseWith this change, Docker Compose will automatically create the volume when you run docker-compose up and can optionally remove it with docker-compose down -v.
Verify that the volume name in your docker-compose.yml matches an existing volume:
# List all volumes on your system
docker volume ls
# Check the exact name Docker Compose expects
docker-compose config | grep -A5 volumes:Common name mismatches:
Project prefix issues:
Docker Compose V1 sometimes prefixes volume names with the project name. If your project directory is myapp, Compose might look for myapp_myvolume instead of myvolume.
Solution using the `name` attribute:
volumes:
myvolume:
external: true
name: myvolume # Use the exact name, ignoring project prefixThis tells Compose to use the literal name myvolume without any prefix.
The name attribute lets you decouple the volume reference in your Compose file from the actual volume name on the system:
services:
database:
image: postgres:15
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
external: true
name: shared_postgres_data # Actual volume name on the systemThis is useful when:
- You want to reference an existing volume with a different name
- The actual volume has a name that doesn't follow your naming conventions
- You want to share volumes between different Compose projects
Create the volume with the name you specified:
docker volume create shared_postgres_dataBefore running docker-compose, check that your volumes exist:
# List all volumes
docker volume ls
# Filter by name pattern
docker volume ls --filter name=myvolume
# Check a specific volume exists
docker volume inspect myvolumeSample output for a healthy volume:
[
{
"CreatedAt": "2024-01-15T10:30:00Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/myvolume/_data",
"Name": "myvolume",
"Options": {},
"Scope": "local"
}
]If the volume doesn't exist, you'll see an error instead of the JSON output.
Docker Compose V1 and V2 can behave differently with external volumes:
Check your version:
# V1 (standalone docker-compose)
docker-compose --version
# V2 (plugin)
docker compose versionV1 syntax (older):
volumes:
myvolume:
external:
name: actual-volume-nameV2 syntax (current):
volumes:
myvolume:
external: true
name: actual-volume-nameIf upgrading from V1 to V2, you may need to update your syntax. There was a known parsing issue in Compose V2.2.0 (GitHub Issue #8992) that affected external volume handling - ensure you're using a recent version:
# Update Docker Compose plugin
docker compose version
# On Linux, update with your package manager
sudo apt update && sudo apt install docker-compose-pluginIf you've accidentally deleted a volume (e.g., with docker volume prune or docker-compose down -v), you'll need to recreate it:
# Check if the volume still exists
docker volume ls | grep myvolume
# If it was deleted, create it again
docker volume create myvolumeImportant: The data in the volume is gone if it was deleted. If you had important data:
1. Check for backups
2. If the data came from a container, you can repopulate it by running the container
3. For databases, restore from your database backup
Prevention tips:
# Use labels to protect important volumes
docker volume create --label=important=true myvolume
# When pruning, be careful
docker volume prune # This will list volumes to be deleted first
# Never use -f flag without checking first
docker volume prune -f # DANGEROUS - no confirmation!For CI/CD environments where volumes don't persist, create them as part of your pipeline:
GitHub Actions example:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create external volumes
run: |
docker volume create myvolume
docker volume create postgres_data
- name: Start services
run: docker-compose up -dGitLab CI example:
test:
script:
- docker volume create myvolume
- docker-compose up -dAlternative - don't use external in CI:
You can also use environment-specific Compose files:
# docker-compose.ci.yml (volumes managed by Compose)
volumes:
myvolume:
# No external flag - Compose creates it# In CI
docker-compose -f docker-compose.yml -f docker-compose.ci.yml up -d### When to Use External Volumes
External volumes are best for:
1. Shared data between projects: When multiple Compose projects need access to the same data
2. Persistent databases: Preventing accidental deletion with docker-compose down -v
3. Pre-provisioned infrastructure: Volumes created by Terraform, Ansible, or other tools
4. Volume plugins: When using storage drivers that require pre-creation (NFS, cloud storage, etc.)
### External Volumes vs Named Volumes
| Feature | External Volume | Named Volume (non-external) |
|---------|----------------|----------------------------|
| Created by | Manual (docker volume create) | Docker Compose |
| Deleted by down -v | No | Yes |
| Shared across projects | Yes | Requires manual setup |
| Requires pre-creation | Yes | No |
| Error if missing | Yes (at startup) | No (created automatically) |
### Volume Naming with Projects
Docker Compose prefixes resources with the project name by default:
# Project name is determined by:
# 1. -p flag: docker-compose -p myproject up
# 2. COMPOSE_PROJECT_NAME env var
# 3. Directory name containing docker-compose.ymlWhen NOT using external: true, a volume named data in a project called myapp becomes myapp_data.
When using external: true, Compose looks for the exact name specified (or uses the name attribute).
### Docker Swarm Considerations
In Swarm mode, external volumes work differently:
volumes:
myvolume:
external: true
# Note: Volume must exist on the node where the task runsSwarm doesn't automatically distribute volumes across nodes. Consider:
- Using a volume plugin with distributed storage
- Using placement constraints to pin services to specific nodes
- Using NFS or other shared storage
### Debugging Volume Issues
# See what Compose thinks the volume configuration is
docker-compose config
# Check volume details
docker volume inspect myvolume
# List volumes with labels
docker volume ls --format "{{.Name}}\t{{.Labels}}"
# Find where a volume is stored
docker volume inspect myvolume --format '{{ .Mountpoint }}'### Migration from Compose V1 to V2
If you're migrating from docker-compose (V1) to docker compose (V2 plugin), note these changes:
1. The external.name syntax is deprecated:
# Old (V1 only)
volumes:
db:
external:
name: actual-name
# New (V1 and V2)
volumes:
db:
external: true
name: actual-name2. Some edge cases with volume parsing were fixed in later V2 releases
3. The --volumes flag behavior with down is consistent in V2
dockerfile parse error line 5: unknown instruction: RRUN
How to fix 'unknown instruction' Dockerfile parse error in Docker
Error response from daemon: manifest for nginx:nonexistent not found: manifest unknown: manifest unknown
How to fix 'manifest for image:tag not found' in Docker
Error response from daemon: invalid reference format: repository name must be lowercase
How to fix 'repository name must be lowercase' in Docker
Error response from daemon: No such image
How to fix 'No such image' in Docker
Error response from daemon: Container is not running
How to fix 'Container is not running' when using docker exec