How to Use Volumes and Bind Mounts for File Sharing with Apple Container
Use the --volume flag to map host directories directly into containers, or create persistent named volumes with container volume create to share data across container restarts and instances.
The container CLI from Apple's open-source repository provides a lightweight virtualization runtime for running OCI-compatible containers on macOS. Learning how to use volumes and bind mounts for file sharing is essential for persisting application state, sharing configuration files from the host, and coordinating data between multiple container instances. This guide documents the exact syntax, underlying architecture, and lifecycle management commands found in the source code.
Bind Mounts vs. Named Volumes
container implements three distinct storage mechanisms for exposing data to containers, each serving different persistence and sharing requirements.
Bind Mounts (Direct Host Access)
Bind mounts directly map a directory or file from the macOS host into the container's filesystem using absolute paths. According to docs/how-to.md, the CLI translates --volume flags into a bind-mount that is passed to the underlying Containerization runtime, which creates a virtual block device for the container VM and attaches the host directory as an FS bind inside that VM.
The syntax requires an absolute pathname:
--volume <host-path>:<container-path>
Host paths must exist before executing container run, and the container sees files with the same permissions as the host user.
Named Volumes (Managed Persistence)
Named volumes are persistent storage objects managed by container via the container volume sub-command family documented in docs/command-reference.md (lines 862-970). Unlike bind mounts, these are not tied to specific host paths but are instead logical volumes that survive container removal and can be attached to multiple containers simultaneously.
Create them with specific filesystem options:
container volume create --opt size=5g --opt journal=ordered mydata
Anonymous Volumes (Automatic Storage)
When you specify a target path without a source (e.g., -v /app/data), container automatically creates an anonymous volume with a UUID-based name prefix (anon-…). As noted in docs/command-reference.md (lines 909-921), these volumes persist until explicitly deleted using container volume delete or container volume prune.
Command Syntax and Architecture
The container run command supports two equivalent flag styles for mounting storage, both documented in the Share host files section of docs/how-to.md (lines 36-53).
Short form (--volume or -v):
container run -v "${HOME}/Desktop/assets:/content/assets" ...
Explicit form (--mount):
container run --mount source="${HOME}/Desktop/assets",target=/content/assets ...
The --mount syntax uses comma-separated key=value pairs, which improves readability when combining multiple options. Both methods ultimately trigger the same VM-level bind-mount mechanism described in docs/technical-overview.md.
Special case: The --ssh flag shortcuts this machinery to mount the macOS SSH socket into containers, demonstrating that any host file can be exposed without additional plumbing (docs/how-to.md, lines 60-62).
Practical Usage Examples
Sharing Host Files with Bind Mounts
Map a local directory into a container to access assets or source code during development:
# Create test data on the host
mkdir -p "${HOME}/Desktop/assets"
echo '<svg>...</svg>' > "${HOME}/Desktop/assets/link.svg"
# Run container with bind mount
container run \
--volume "${HOME}/Desktop/assets:/content/assets" \
docker.io/python:alpine \
ls -l /content/assets
The output confirms the file appears inside the container at /content/assets.
Creating and Using Named Volumes
Named volumes provide durable storage independent of container lifecycle:
# Create a 5 GiB volume with ext4 journaling
container volume create \
--opt size=5g \
--opt journal=ordered \
mydata
# Attach to a container and write data
container run \
-v mydata:/app/data \
docker.io/alpine:latest \
touch /app/data/marker.txt
# Verify persistence in a new container instance
container run \
-v mydata:/app/data \
docker.io/alpine:latest \
cat /app/data/marker.txt
Handling Anonymous Volumes
Anonymous volumes are ideal for temporary cache directories that should persist across container restarts but not clutter the host filesystem:
# Trigger automatic volume creation
container run -v /tmp/cache docker.io/alpine:latest touch /tmp/cache/file
# Locate the generated name (format: anon-<uuid>)
VOL=$(container volume list -q | grep anon)
echo "Anonymous volume: $VOL"
# Clean up when no longer needed
container volume delete "$VOL"
Volume Lifecycle Management
Manage persistent storage using the container volume subcommands:
# List all volumes (named and anonymous)
container volume list
# Inspect metadata and configuration in JSON format
container volume inspect mydata
# Remove a specific unused volume
container volume delete mydata
# Remove all unused volumes
container volume prune
Summary
- Bind mounts (
-v /host/path:/container/path) map absolute host paths directly into the container VM filesystem, requiring the path to exist before running the container. - Named volumes created via
container volume createpersist data across container deletions and support configuration options like size limits and filesystem journaling. - Anonymous volumes are auto-generated when specifying only a container path, receiving UUID-based names (
anon-…) and persisting until manually pruned. - The
--mountsyntax offers an explicitkey=valuealternative to--volume, improving readability for complex mount configurations. - All volume mechanisms leverage the same underlying Containerization runtime architecture that attaches host directories as FS binds inside the virtual machine.
Frequently Asked Questions
What is the difference between --volume and --mount syntax in container?
Both flags achieve the same underlying bind-mount behavior, but --volume uses a concise colon-separated format (host:container) while --mount uses explicit comma-separated key-value pairs (source=...,target=...). The --mount syntax reduces ambiguity when specifying additional options and is preferred for complex configurations or named volume references.
Why must host paths be absolute when using bind mounts?
The container CLI requires absolute pathnames for host directories to ensure the Containerization runtime can correctly resolve and attach the filesystem to the virtual machine's block device. Relative paths are rejected because the daemon process runs in a different context than the user's shell.
How do I share data between multiple containers?
Create a named volume using container volume create <name> and attach it to multiple containers using -v <name>:/path. Unlike bind mounts, named volumes are managed by the container daemon and persist independently of any single container's lifecycle, allowing seamless data sharing across container instances.
Can I limit the size of a persistent volume?
Yes. When creating a named volume with container volume create, pass the --opt size=<value> flag to enforce capacity limits. For example, --opt size=5g creates a 5-gigabyte volume. You can also specify filesystem-specific options like --opt journal=ordered for ext4 volumes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →