# How to Create and Manage Persistent Storage Volumes for Containers in Apple Container

> Learn to create and manage persistent storage volumes for containers with Apple Container's volume subsystem. Ensure data survives restarts and shares across containers.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: how-to-guide
- Published: 2026-07-12

---

**The Apple Container project provides a built-in volume subsystem that lets you create, list, inspect, and delete persistent storage volumes that survive container restarts and can be shared across multiple containers.**

The `apple/container` repository implements a complete volume management API that handles persistent storage independently of container images. These volumes live on the host filesystem and are managed by the `ContainerAPIClient`, ensuring data persists beyond individual container lifecycles. Understanding how to create and manage persistent storage volumes for containers is essential for stateful workloads and data sharing between container instances.

## Understanding Volume Types and Concepts

The Container project distinguishes between several volume types, each with specific use cases and validation rules.

### Named Volumes

**Named volumes** are explicitly created using `container volume create <name>` or implicitly when using the `-v <name>:/path` flag. Names must match the `VolumeResource.volumeNamePattern` regex (`^[A-Za-z0-9][A-Za-z0-9_.-]*$`) and are capped at 255 characters according to the validation logic in [`Sources/ContainerResource/Volume/VolumeResource.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Volume/VolumeResource.swift).

### Anonymous Volumes

**Anonymous volumes** are auto-generated when you omit the host path in mount flags (using `-v /path` or `--mount type=volume,dst=/path`). The system assigns a UUID-based name following the pattern `anon-<36-char-uuid>` and marks it via the `VolumeConfiguration.isAnonymous` flag derived from special labels added by the daemon.

### Driver-Specific Options

The default `local` driver supports custom options passed via `--opt key=value`. Key options include:
- **`size`**: Specifies volume capacity (e.g., `10g`)
- **`journal`**: Configures ext4 journaling mode (`ordered`, `writeback`, or `writeback:64m` for custom journal size)

### Labels and Metadata

Arbitrary key/value metadata can be attached using `--label <key>=<value>`. These labels are validated by `ResourceLabels` and stored in `VolumeConfiguration.labels` as implemented in [`VolumeResource.swift`](https://github.com/apple/container/blob/main/VolumeResource.swift).

## Volume Lifecycle Rules

The Container project enforces strict rules to prevent data loss:

- **Attachment blocking**: A volume cannot be deleted while attached to any container, whether running or stopped.
- **Anonymous persistence**: Unlike Docker behavior, anonymous volumes are **not** automatically removed when using `--rm` on containers. They must be deleted manually via `container volume delete`.
- **Multi-container sharing**: Volumes can be attached to multiple containers simultaneously, enabling shared state between instances.

## Architecture Overview

The volume subsystem follows a client-server architecture with clear separation between API and resource representation.

### VolumeResource

`VolumeResource` (defined in [`Sources/ContainerResource/Volume/VolumeResource.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Volume/VolumeResource.swift)) is a lightweight wrapper conforming to `ManagedResource`. It exposes:
- Volume ID and name
- Creation timestamp
- Label metadata
- Anonymity flag (`isAnonymous`)

This struct enables generic CLI handling across the framework while wrapping the underlying `VolumeConfiguration` objects.

### ClientVolume and API Flow

The `ClientVolume` client (part of `ContainerAPIClient`) handles RPC communication with the daemon. Key methods include:
- `list()`: Fetches all volume configurations from the daemon
- `create()`: Sends volume creation RPCs with driver options
- `delete()`: Removes volumes after verifying no attachments exist

CLI commands in `Application.VolumeCommand` parse user flags, invoke these `ClientVolume` methods, translate results into `VolumeResource` instances, and render output via the generic `Output` helper (as seen in [`Sources/ContainerCommands/Volume/VolumeList.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Volume/VolumeList.swift) and [`Sources/ContainerCommands/Volume/VolumeInspect.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Volume/VolumeInspect.swift)).

## Creating Persistent Storage Volumes

Create named volumes with specific capacity and journaling modes using the `container volume create` command.

Create a 10 GiB volume with ordered journaling:

```bash
container volume create -s 10g --opt journal=ordered mydata

```

Create a volume with writeback journaling and custom journal size:

```bash
container volume create --opt journal=writeback:64m myfastvol

```

Create a volume with custom labels:

```bash
container volume create --label environment=production --label tier=database pgdata

```

## Listing and Inspecting Volumes

View all volumes in table format or extract specific names for scripting.

List all volumes with details:

```bash
container volume list

```

List only volume names (quiet mode):

```bash
container volume list -q

```

Inspect a specific volume's metadata, driver options, and usage:

```bash
container volume inspect mydata

```

## Attaching Volumes to Containers

Mount existing volumes or create anonymous volumes during container runtime.

Attach a named volume to a container:

```bash
container run -v mydata:/app/data alpine sh

```

Use the `--mount` syntax for explicit volume type declaration:

```bash
container run --mount type=volume,src=mydata,dst=/app/data alpine sh

```

Create and mount an anonymous volume (auto-generates UUID-based name):

```bash
container run -v /tmp/cache alpine sh

```

Reuse an existing anonymous volume by referencing its generated name:

```bash
VOL=$(container volume list -q | grep anon)
container run -v $VOL:/app/cache alpine sh

```

## Deleting Volumes

Remove volumes that are no longer in use, with safety checks for attached containers.

Delete a specific volume (fails if still attached):

```bash
container volume delete mydata

```

Delete all volumes (use with caution):

```bash
container volume delete --all

```

Clean up anonymous volumes manually (since they persist after container removal):

```bash
container volume list -q | grep anon | xargs container volume delete

```

## Summary

- **Named volumes** require alphanumeric names matching `^[A-Za-z0-9][A-Za-z0-9_.-]*$` and support driver options for size and journaling.
- **Anonymous volumes** auto-generate UUID-based names (`anon-<uuid>`) and persist after container removal unless manually deleted.
- **Lifecycle protection** prevents deletion of attached volumes, while the `VolumeResource` struct in [`VolumeResource.swift`](https://github.com/apple/container/blob/main/VolumeResource.swift) wraps daemon configurations for CLI presentation.
- **Driver options** for the `local` driver include `size` capacity limits and `journal` mode configuration for ext4 filesystems.
- The `ClientVolume` API in `ContainerAPIClient` handles create, list, inspect, and delete operations, with CLI implementations residing in [`VolumeList.swift`](https://github.com/apple/container/blob/main/VolumeList.swift) and [`VolumeInspect.swift`](https://github.com/apple/container/blob/main/VolumeInspect.swift).

## Frequently Asked Questions

### What's the difference between named and anonymous volumes?

**Named volumes** are explicitly created with `container volume create` or referenced by name in mount flags, persist until manually deleted, and support custom driver options. **Anonymous volumes** are auto-generated when using `-v /path` without a host name, receive a UUID-based name (`anon-<36-char-uuid>`), and are marked via the `isAnonymous` flag in `VolumeConfiguration`.

### Can I delete a volume while it's attached to a container?

No. The Container project enforces attachment validation before deletion. The `container volume delete` command will fail if the volume is mounted by any container, regardless of whether that container is running or stopped. You must stop and remove all referencing containers before the volume can be deleted.

### How do I configure volume size and journaling options?

Pass driver-specific options using `--opt` flags during creation. The default `local` driver accepts `size` (e.g., `-s 10g` or `--opt size=10g`) and `journal` settings (`--opt journal=ordered` or `--opt journal=writeback:64m`). These options configure the underlying ext4 filesystem during volume initialization.

### Do anonymous volumes get automatically removed when the container stops?

No. Unlike some container runtimes, anonymous volumes in the Apple Container project **do not** get removed when using `--rm` on containers. They persist on the host filesystem and require manual deletion via `container volume delete <anon-uuid>` or `container volume delete --all` when no longer needed.