still useful today, or long replaced?
Before Docker officially supported named volumes, the community solved the problem of persistent data with a workaround: a dedicated, never running container that only declared data directories and passed them on to other containers via --volumes-from. This data-only container pattern was standard for years, but is now replaced by named volumes in the vast majority of cases, with only a few remaining niches where the old approach still plays a role.
Table of Contents
- 1. Where the data-only container pattern comes from
- 2. How the pattern worked in practice
- 3. Why named volumes made the pattern nearly obsolete
- 4. The drawbacks of the old pattern in hindsight
- 5. Migrating existing data-only containers
- 6. Remaining niches: where the pattern still shows up
- 7. Comparison to Kubernetes init containers
- 8. Detecting and cleaning up old Compose files
- 9. Data-only container vs. named volumes compared
- 10. Summary
- 11. FAQ
1. Where the data-only container pattern comes from
In the early versions of Docker, long before named volumes existed as a standalone, named construct, there were only anonymous volumes and bind mounts. Anyone who wanted to share data between multiple containers without committing to a fixed host path had to take a detour: the data-only container pattern. This involved creating a container solely for the purpose of declaring one or more volumes, without itself running a process that lasted longer than the initial start.
Other containers could then attach to this data container via the --volumes-from parameter and reuse its volumes, even after the data container itself had long since stopped. The data-only container pattern was, in its time, the only practical solution for keeping data independent of an application container's lifecycle and sharing it across multiple containers, but it became largely obsolete with the introduction of named volumes in Docker 1.9 in 2015.
2. How the pattern worked in practice
A classic data-only container was typically created with a minimal image like busybox and declared one or more volumes via the VOLUME instruction in the Dockerfile or the -v parameter with docker create. The container itself often ran no meaningful process and was never started again after creation, serving only as a reference point for the declared volumes.
Other containers then accessed exactly the same volume mounts with docker run --volumes-from data-container, without having to specify the volume path themselves again. This data-only container pattern thus solved two problems at once: it made volumes shareable between containers without requiring a fixed host path, and it fully decoupled the lifecycle of the data from the lifecycle of every individual application container using it.
#!/usr/bin/env bash
# legacy-data-only-container.sh — historical pattern, shown for reference
set -euo pipefail
# Create a data-only container (never actually runs a real process)
docker create -v /var/lib/mysql --name mysql-data busybox
# Application containers reference the data container's volumes
docker run -d --volumes-from mysql-data --name mysql-app1 mysql:5.7
docker run -d --volumes-from mysql-data --name mysql-app2 mysql:5.7
# Data survives even if the data-only container is removed
# (as long as another container still references its volumes)
docker inspect mysql-data --format '{{ .Mounts }}'
3. Why named volumes made the pattern nearly obsolete
With Docker 1.9, the Docker team introduced named volumes, which solve exactly the problems that the data-only container pattern previously served as a workaround for. A docker volume create myvolume creates a standalone, named volume that exists independent of any container and can be referenced directly by its name, without needing a detour through an additional, never running container.
The decisive advantage of named volumes over the data-only container pattern lies in direct manageability: volumes can be managed independently with docker volume ls, docker volume inspect, and docker volume rm, while a data container always produced an extra, semantically confusing entry in the container list, even though it never actually ran. This clarity in the Docker API was the main reason named volumes established themselves as the standard solution within a few years and displaced the older pattern in the vast majority of setups.
4. The drawbacks of the old pattern in hindsight
In hindsight, it turns out that the data-only container pattern had several structural weaknesses that were accepted as a necessary evil at the time. The data container itself appeared in docker ps -a as a stopped container, which frequently led to accidental deletion by automated cleanup scripts if those scripts removed all stopped containers indiscriminately, without distinguishing between real application containers and pure data references.
A second structural problem was the lack of clarity about which containers actually depended on a data-only container. Since the dependency was established at runtime via --volumes-from and was not visible in a central, declarative configuration, teams often had to manually trace which application containers would be affected when removing a data container. Named volumes solve this problem through explicit referencing in the Compose file or the docker run command, making dependencies immediately visible.
5. Migrating existing data-only containers
Anyone who still encounters a historically grown data-only container pattern in a production environment today should schedule migration to named volumes as a standard task, not as optional cleanup. The first step is to copy the actual data from the data container's anonymous volume into a new, named volume, while all dependent application containers are briefly stopped to ensure consistency.
After a successful copy, the application containers get recreated, this time with a direct reference to the new named volume instead of --volumes-from. Only once all application containers have successfully switched to the new volume and functionality has been verified should the old data-only container be removed along with its anonymous volume. This step by step approach avoids an incomplete migration causing data loss.
#!/usr/bin/env bash
# migrate-data-container-to-named-volume.sh
set -euo pipefail
OLD_DATA_CONTAINER="mysql-data"
NEW_VOLUME="mysql-data-named"
# 1. Create the new named volume
docker volume create "$NEW_VOLUME"
# 2. Stop dependent application containers for a consistent copy
docker stop mysql-app1 mysql-app2
# 3. Copy data from the anonymous volume into the new named volume
docker run --rm \
--volumes-from "$OLD_DATA_CONTAINER" \
-v "${NEW_VOLUME}:/target" \
alpine sh -c "cp -a /var/lib/mysql/. /target/"
# 4. Recreate application containers referencing the named volume directly
docker rm mysql-app1 mysql-app2
docker run -d --name mysql-app1 -v "${NEW_VOLUME}:/var/lib/mysql" mysql:5.7
docker run -d --name mysql-app2 -v "${NEW_VOLUME}:/var/lib/mysql" mysql:5.7
# 5. Once verified, remove the legacy data-only container
docker rm "$OLD_DATA_CONTAINER"
echo "[OK] Migration to named volume complete"
6. Remaining niches: where the pattern still shows up
Despite being largely replaced by named volumes, the data-only container pattern occasionally still appears in two contexts. The first is historically grown legacy code that has run unchanged in production for years and where nobody has prioritized migration, because the system works and a rework is perceived as a risk without immediate benefit. Such systems are found mainly in companies that started with Docker early and have changed little at the storage layer since.
The second remaining use case is conceptually related but not identical: the pattern of a dedicated init container that writes data into a volume once at startup, such as initial configuration files or seed data, before the actual application container starts. However, this modern descendant of the data-only container pattern always uses a named volume as its target, no longer an anonymous volume of a never running container, and thus differs structurally from the historical original.
7. Comparison to Kubernetes init containers
It is interesting that the basic idea behind the data-only container pattern, namely a container that prepares data for other containers, reappears in Kubernetes as an official, first class concept: the init container. A Kubernetes init container runs before the actual application containers of a pod, can pre populate volumes, and then terminates normally, while the populated volume becomes available to the main container.
The difference from the original data-only container pattern is that Kubernetes init containers exist as an explicit, documented API concept with a clear execution order, while the Docker pattern was an informal community workaround with no native support. Anyone who needs init logic for volumes today, such as pre populating with seed data, should rely on an explicit init service with depends_on and a success condition in Docker Compose, rather than rebuilding the old data-only container pattern.
8. Detecting and cleaning up old Compose files
A reliable indicator of a still active data-only container pattern in an existing Compose file is the use of the volumes_from keyword, which was officially removed since Compose file version 3 and should no longer appear in modern setups. If this key is found in a legacy Compose file, it is a clear signal that a migration to named volumes is still outstanding.
A simple grep across all Compose files in a project reliably surfaces such legacy remnants before they cause a hard failure during an upgrade to a newer Compose version, because the syntax is simply no longer supported. Anyone who regularly checks Compose files for outdated syntax avoids nasty surprises at the next major Docker or Compose upgrade and ensures that no data-only container pattern silently lives on in production.
#!/usr/bin/env bash
# find-legacy-pattern.sh — scan for deprecated volumes_from usage
set -euo pipefail
echo "[INFO] Scanning for legacy volumes_from directive..."
if grep -rn "volumes_from" --include="docker-compose*.yml" .; then
echo "[WARN] Legacy Data-Only-Container pattern detected — migrate to named volumes"
exit 1
else
echo "[OK] No legacy volumes_from usage found"
fi
9. Data-only container vs. named volumes compared
The following table directly compares the historical data-only container pattern with the modern named volume approach.
| Aspect | Data-Only Container | Named Volume |
|---|---|---|
| Management | Via container commands, indirect | Directly via docker volume |
| Visibility in docker ps | Appears as a (stopped) container | No entry in the container list |
| Cleanup risk | High, accidental removal possible | Low, explicit volume management |
| Compose support | volumes_from, removed since v3 | Native volumes directive |
| Recommendation today | Legacy systems only, migrate | Standard for all new setups |
The table makes clear that there is practically no longer any reason to use the data-only container pattern in new projects. Named volumes offer the same core functionality, namely shareable data management decoupled from the container lifecycle, without the structural drawbacks of the old approach.
Mironsoft
Docker modernization, legacy migration, and current storage best practices
Still running old data-only containers in production? Time to migrate.
We identify outdated storage patterns in your Docker setups and migrate them safely to named volumes, without data loss and with full verification before decommissioning the old approach.
Legacy Audit
Detecting volumes_from and other outdated storage patterns
Safe Migration
Step by step move to named volumes with consistency checks
Modernization
Current Compose syntax and up to date storage architecture
10. Summary
The data-only container pattern was a clever stopgap from a time when Docker did not yet know named volumes, and it solved a real problem back then: making data shareable independent of the container lifecycle. Since the introduction of named volumes in Docker 1.9, this pattern has become superfluous in almost all cases, because named volumes offer the same functionality more directly, more visibly, and without the cleanup risks of the old approach.
Anyone who still encounters a data-only container pattern in a production environment today should treat migration to named volumes as a mandatory task, not as optional cleanup. The few remaining niches, such as historically grown legacy systems or init like pre population logic, do not justify deliberately reusing the old pattern in new projects.
Data-Only Container Pattern — Key Takeaways at a Glance
Historical Context
A workaround from before Docker 1.9, when named volumes did not yet exist.
Named Volumes as Replacement
Direct, visible management via docker volume instead of indirect container references.
Detection Marker
The volumes_from key in Compose files is a clear signal of pending migration.
Recommendation Today
Use named volumes exclusively for all new projects, only migrate the old pattern, never rebuild it.