Is the Data-Only Container Pattern Still Useful?
AI generated
FROM
RUN
Docker · Storage · History · Best Practices
Data-Only Container Pattern
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.

16 min read Data-Only Container · Named Volumes · Legacy Docker 1.9+ through Docker 25+

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.

11. FAQ: Data-Only Container Pattern

1What was the data-only container pattern?
Early Docker workaround: never running container declared volumes, others used them via --volumes-from.
2Still useful today?
Almost never. Named volumes solve the same problem more directly and without cleanup risks.
3Why replaced?
Named volumes are directly manageable via docker volume, without a confusing container entry.
4How do I recognize it?
The volumes_from key in a Compose file is the clear signal.
5How to migrate?
Copy data into a new named volume, then recreate containers with a direct volume reference.
6Any legitimate cases remaining?
Only in historical legacy code. No reason to reuse for new projects.
7Difference to Kubernetes init containers?
Init containers are an official API concept, the Docker pattern was an informal workaround.
8Cleanup risk?
Automated scripts can accidentally delete the data container.
9Does volumes_from still work?
No, officially removed since Compose file version 3.
10Should I migrate regardless?
Yes, to avoid cleanup risks and compatibility problems with future upgrades.