> For the complete documentation index, see [llms.txt](https://v2.dataos.info/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://v2.dataos.info/references/dataos-resources/volume.md).

# Volume

A Volume is a DataOS Resource that provisions persistent, cloud-backed block storage on a specified dataplane. Use a Volume when data written by a workload must survive a redeploy, a pod restart, or a hand-off to a different workload.

A Volume's lifecycle is independent of any workload. You create it once, mount it into a Service, Worker, or Workflow with `use.volumes`, and it keeps existing after that workload is updated or deleted.

## Access requirements

Creating a Volume requires tenant-specific roles. To use an existing Volume — mounting it into a Service, Worker, or Workflow — the Volume's owner must grant you permission to use it.

## When to use

Use a Volume when you need to:

* Persist data across workload redeploys and deletes.
* Hand off a dataset between pipeline stages that run at different times.
* Share a dataset sequentially across a Service, Worker, or Workflow.
* Manage storage sizing and lifecycle independently of the application that uses it.

If the storage instead belongs entirely to a single workload's lifecycle, for example a database data directory or a scratch buffer, declare it inline with `disk` instead. See [Two ways to attach storage](#two-ways-to-attach-storage).

## Key characteristics

* **Cloud block storage:** Backed by managed cloud disks with high-speed, durable storage.
* **One pod at a time:** A Volume can only be mounted by a single pod at any given time, which keeps writes consistent.
* **Dataplane targeting:** Each Volume is provisioned on a specific dataplane.
* **In-place resizing:** Expand a Volume by re-applying its manifest with a larger `size`; no migration or data loss.
* **Tenant-scoped:** Accessible across the entire tenant, not restricted to a single workspace.
* **Automated cleanup:** When a Volume is deleted, the underlying cloud disk is reclaimed automatically within 30 days.

## Manifest structure

A Volume manifest uses the common Resource metadata fields and a `volume` section that defines the storage.

{% tabs %}
{% tab title="Syntax" %}

```yaml
name: ${{volume-name}}
version: v2alpha
type: volume
description: ${{description}}
volume:
  size: ${{size}}              # Kubernetes quantity, e.g. 10Gi, 100Mi, 1Ti
  type: disk                   # Only "disk" is supported
  dataplane: ${{dataplane-name}}
```

{% endtab %}

{% tab title="Example" %}

```yaml
name: volume-int-test-01
version: v2alpha
type: volume
description: "Persistent storage for volume integration test"
tags:
  - volume
  - integration-test
volume:
  size: 2Gi
  type: disk
  dataplane: ${DATAPLANE_NAME}
```

{% endtab %}
{% endtabs %}

After applying, retrieve the system-generated `volumeId` with `dataos-ctl resource get -t volume -n volume-int-test-01 -d` — it appears under `status.activeProperties.volumeId` in the detail output. Use that `volumeId`, not the resource name, as the `id` in `use.volumes` when mounting this Volume. See [Get the volumeId](#get-the-volumeid).

## Two ways to attach storage

Every runnable workload (Service, Worker, Workflow) needs a decision on where its files live. DataOS offers two mechanisms, and the right one depends on whether the data should outlive the workload.

| Criteria                    | Existing Volume (`use.volumes`) | Inline disk (`disk`)               |
| --------------------------- | ------------------------------- | ---------------------------------- |
| Data outlives the workload? | Yes                             | No                                 |
| Shared across workloads?    | Yes, sequentially               | No                                 |
| Separate lifecycle?         | Yes                             | No                                 |
| Self-contained manifest?    | No — needs a pre-created Volume | Yes                                |
| Supported resources         | Service, Worker, Workflow       | Service (`stateful: true`), Worker |

### Persist storage across workloads (`use.volumes`) <a href="#persist-storage-across-workloads-use-volumes" id="persist-storage-across-workloads-use-volumes"></a>

Create a standalone Volume Resource, then reference it from a Service, Worker, or Workflow step with `use.volumes`. The Volume's lifecycle stays independent of the workload — deleting the workload does not delete the Volume.

```yaml
use:
  volumes:
    - id: ${{volume-id}}          # System-generated volumeId — see below
      directory: ${{mount-path}}
      readOnly: ${{true|false}}   # Optional, default false
      subPath: ${{sub-directory}} # Optional
```

Best for shared application state, hand-off between pipeline stages, and data that must persist across redeploys.

{% tabs %}
{% tab title="Service" %}

```yaml
name: svc-with-volume-01
version: v2alpha
type: service
description: "Service with persistent volume mount for volume integration test"
tags:
  - volume
  - service
  - integration-test
spec:
  replicas: 1
  hostname: svc-vol-test
  compute: ${COMPUTE_NAME}
  runAsUser: ${DATAOS_USER}
  stack: container
  servicePorts:
    - name: http
      port: 8080
  use:
    volumes:
      - id: ${VOLUME_ID}           # From status.activeProperties.volumeId, NOT the resource name
        directory: /app/data
        readOnly: false
  stackSpec:
    image: alpine:3.19
    command:
      - /bin/sh
      - -c
      - |
        echo "Volume mounted at /app/data"
        ls -la /app/data
        while true; do sleep 30; done
```

{% endtab %}

{% tab title="Worker" %}

```yaml
name: worker-with-volume-01
version: v2alpha
type: worker
description: "Worker with persistent volume mount for volume integration test"
tags:
  - volume
  - worker
  - integration-test
spec:
  replicas: 1
  compute: ${COMPUTE_NAME}
  runAsUser: ${DATAOS_USER}
  stack: container
  use:
    volumes:
      - id: ${VOLUME_ID}           # From status.activeProperties.volumeId, NOT the resource name
        directory: /var/dataos/shared
        readOnly: false
  stackSpec:
    image: alpine:3.19
    command:
      - /bin/sh
      - -c
      - |
        echo "Volume mounted at /var/dataos/shared"
        echo "worker-run-$(date +%s)" >> /var/dataos/shared/runs.log
        cat /var/dataos/shared/runs.log
        while true; do sleep 30; done
```

{% endtab %}

{% tab title="Workflow" %}

```yaml
name: wf-with-volume-01
version: v2alpha
type: workflow
description: "Workflow with persistent volume mount for volume integration test"
tags:
  - volume
  - workflow
  - integration-test
workflow:
  dag:
    - name: volume-write-step
      title: "Write data to mounted volume"
      spec:
        stack: container
        compute: ${COMPUTE_NAME}
        runAsUser: ${DATAOS_USER}
        use:
          volumes:
            - id: ${VOLUME_ID}     # From status.activeProperties.volumeId, NOT the resource name
              directory: /mnt/staging
        stackSpec:
          image: alpine:3.19
          command:
            - /bin/sh
            - -c
            - |
              echo "Volume mounted at /mnt/staging"
              echo "workflow-run-$(date +%s)" >> /mnt/staging/workflow-runs.log
              cat /mnt/staging/workflow-runs.log
              echo "Done"
```

{% endtab %}
{% endtabs %}

### Provision storage inline with a workload (`disk`) <a href="#provision-storage-inline-with-a-workload-disk" id="provision-storage-inline-with-a-workload-disk"></a>

Declare storage directly inside a workload manifest with a `disk` block. No separate Volume Resource is needed — the disk is provisioned when the workload deploys and deleted when the workload is removed.

```yaml
disk:
  size: ${{size}}
  type: disk
  mountPath: ${{mount-path}}
```

Best for database data directories, local caches, spill-to-disk buffers, and other ephemeral scratch space.

{% tabs %}
{% tab title="Service" %}

```yaml
name: svc-with-inline-disk-01
version: v2alpha
type: service
description: "Stateful service with inline disk for volume integration test"
tags:
  - volume
  - inline-disk
  - service
  - integration-test
spec:
  replicas: 1
  stateful: true                  # required for inline disk on services
  hostname: svc-disk-test
  compute: ${COMPUTE_NAME}
  runAsUser: ${DATAOS_USER}
  stack: container
  servicePorts:
    - name: http
      port: 5432
  disk:
    size: 2Gi
    type: disk
    mountPath: /var/lib/data
  stackSpec:
    image: alpine:3.19
    command:
      - /bin/sh
      - -c
      - |
        echo "Inline disk mounted at /var/lib/data"
        df -h /var/lib/data
        while true; do sleep 30; done
```

{% endtab %}

{% tab title="Worker" %}

```yaml
name: worker-with-inline-disk-01
version: v2alpha
type: worker
description: "Worker with inline disk for volume integration test"
tags:
  - volume
  - inline-disk
  - worker
  - integration-test
spec:
  replicas: 1
  compute: ${COMPUTE_NAME}        # Workers do not require stateful: true for inline disk
  runAsUser: ${DATAOS_USER}
  stack: container
  disk:
    size: 20Gi
    type: disk
    mountPath: /var/log/collected
  stackSpec:
    image: alpine:3.19
    command:
      - /bin/sh
      - -c
      - |
        echo "Inline disk mounted at /var/log/collected"
        while true; do
          echo "$(date) - log entry" >> /var/log/collected/app.log
          sleep 15
        done
```

{% endtab %}
{% endtabs %}

## Get the volumeId

`use.volumes[].id` requires the system-generated `volumeId`, not the Volume's resource `name`. After creating a Volume, retrieve the `volumeId` before deploying any workload that mounts it:

```bash
dataos-ctl resource get -t volume -n volume-int-test-01 -d
```

Look for `status.activeProperties.volumeId` in the output:

```yaml
status:
  activeProperties:
    volumeId: volumev2alphavolumeinttest01-lbdp
```

{% hint style="warning" %}
Applying a workload with the Volume's resource `name` instead of its `volumeId` in `use.volumes[].id` fails at deploy time. Always read `volumeId` from `status.activeProperties` after the Volume is active.
{% endhint %}

## Apply and manage

Create the Volume:

```bash
dataos-ctl resource apply -f volume.yaml
```

List your Volumes:

```bash
dataos-ctl resource get -t volume
```

Inspect a specific Volume, including its `volumeId`:

```bash
dataos-ctl resource get -t volume -n volume-int-test-01 -d
```

Resize a Volume by increasing `volume.size` in its manifest and re-applying:

```bash
dataos-ctl resource apply -f volume.yaml
```

Delete the workloads mounting the Volume first, then delete the Volume itself — deleting a workload does not delete a Volume it mounted with `use.volumes`:

```bash
dataos-ctl resource delete -t service -n svc-with-volume-01
dataos-ctl resource delete -t worker -n worker-with-volume-01
dataos-ctl resource delete -t workflow -n wf-with-volume-01

dataos-ctl resource delete -t volume -n volume-int-test-01
```

Inline-disk workloads delete their disk along with the workload — no separate cleanup step:

```bash
dataos-ctl resource delete -t service -n svc-with-inline-disk-01
dataos-ctl resource delete -t worker -n worker-with-inline-disk-01
```

{% hint style="info" %}
Deleting a workload never deletes a Volume it mounted with `use.volumes` — the Volume keeps existing until you delete it explicitly. Deleting a workload that used an inline `disk` deletes that disk along with it.
{% endhint %}

## Field reference

| Field                     | Description                                                                                            | Required                        |
| ------------------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------- |
| `name`                    | Volume Resource name.                                                                                  | Yes                             |
| `version`                 | Manifest version. Use `v2alpha`.                                                                       | Yes                             |
| `type`                    | Resource type. Use `volume`.                                                                           | Yes                             |
| `description`             | Human-readable description of the Volume.                                                              | No                              |
| `volume`                  | Volume-specific configuration.                                                                         | Yes                             |
| `volume.size`             | Requested storage size, as a Kubernetes quantity such as `10Gi` or `1Ti`.                              | Yes                             |
| `volume.type`             | Storage type. Use `disk`.                                                                              | Yes                             |
| `volume.dataplane`        | Dataplane where the Volume is provisioned.                                                             | Yes                             |
| `use.volumes[].id`        | Volume's system-generated `volumeId` (from `status.activeProperties.volumeId`), not its resource name. | Yes, when `use.volumes` is used |
| `use.volumes[].directory` | Mount path inside the container.                                                                       | Yes, when `use.volumes` is used |
| `use.volumes[].readOnly`  | Mounts the Volume as read-only when set to `true`. Default `false`.                                    | No                              |
| `use.volumes[].subPath`   | Mounts a sub-directory within the Volume instead of its root.                                          | No                              |
| `disk.size`               | Requested inline disk size, as a Kubernetes quantity such as `10Gi`.                                   | Yes, when `disk` is used        |
| `disk.type`               | Inline storage type. Use `disk`.                                                                       | Yes, when `disk` is used        |
| `disk.mountPath`          | Mount path inside the container.                                                                       | Yes, when `disk` is used        |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://v2.dataos.info/references/dataos-resources/volume.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
