> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mixpeek.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Bring Your Own Object Storage

> Back the Mixpeek Vector Store with your own S3-compatible or GCS bucket on dedicated and self-hosted deployments

The Mixpeek Vector Store (MVS) persists everything it owns — the write-ahead log, snapshots, and the cold tier — to object storage through a provider-agnostic layer. On **dedicated and self-hosted deployments** you can point that layer at your own bucket, on any supported provider, so your vector data lives in storage you control.

> [!NOTE]
>
> This is about where MVS **stores its own data**, not where you ingest from. To connect a bucket as an ingestion *source*, see [Object Storage Integrations](https://docs.mixpeek.com/docs/integrations/object-storage/overview.md). The managed shared plane uses Mixpeek-operated storage; BYO object storage applies to [single-tenant](https://docs.mixpeek.com/docs/resources/single-tenant.md) and self-hosted deployments and is configured at the deployment level (not a per-namespace setting).

## Supported providers

MVS speaks the S3 API (via boto3) and the native GCS API. Any S3-compatible store works through the same code path — the only per-provider differences are the endpoint, region, and path-style addressing.

| Provider | `MVS_OBJECT_STORE_PROVIDER` | Docs |
| - | - | - |
| Amazon S3 | `s3` | [S3](https://docs.mixpeek.com/docs/integrations/object-storage/s3.md) |
| Google Cloud Storage | `gcs` | [GCS](https://docs.mixpeek.com/docs/integrations/object-storage/gcs.md) |
| Cloudflare R2 | `r2` | [R2](https://docs.mixpeek.com/docs/integrations/object-storage/r2.md) |
| Tigris | `tigris` | [Tigris](https://docs.mixpeek.com/docs/integrations/object-storage/tigris.md) |
| Wasabi | `wasabi` | [Wasabi](https://docs.mixpeek.com/docs/integrations/object-storage/wasabi.md) |
| Backblaze B2 | `b2` | [Backblaze](https://docs.mixpeek.com/docs/integrations/object-storage/backblaze.md) |
| MinIO | `minio` | S3-compatible |
| DigitalOcean Spaces | `spaces` | S3-compatible |
| Ceph | `ceph` | S3-compatible |
| LocalStack (dev) | `localstack` | S3-compatible |

See all providers in the [Object Storage overview](https://docs.mixpeek.com/docs/integrations/object-storage/overview.md).

Local and parallel filesystems, including Lustre, are in [private beta](#local-and-parallel-filesystems-private-beta).

## Configuration

The API, coordinator, and Ray worker pods read the object-store backend from these environment variables. The shard reads its own set, listed under [Shard settings](#shard-settings).

| Variable | Default | Description |
| - | - | - |
| `MVS_OBJECT_STORE_PROVIDER` | `gcs` | Provider key from the table above. |
| `MVS_BUCKET` | — | Bucket that holds all MVS data. (Legacy alias: `MVS_GCS_BUCKET` — both must name the same bucket.) |
| `MVS_OBJECT_STORE_ENDPOINT` | — | Custom S3 endpoint. **Required** for R2, Tigris, and Wasabi; optional for MinIO/Ceph. |
| `MVS_REGION` | — | Region for S3-compatible providers. |
| `MVS_PREFIX` | `mvs/` | Global key prefix for all objects. |
| `MVS_ENCRYPTION_KEY` | — | Optional base64-encoded 32-byte key to encrypt all data at rest (see below). |

> [!WARNING]
>
> The coordinator and the Rust shard must read the **same** bucket. Set `MVS_BUCKET` (or `MVS_GCS_BUCKET`) consistently across both — a split here causes cross-tenant namespace discovery. MVS fails fast if the two env vars disagree.

### Credentials

Credentials are never stored in config — they're resolved from the deployment environment:

* **S3-compatible:** the standard AWS credential chain. Prefer an **IAM role** attached to the pods; otherwise set `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`. R2/Tigris/Wasabi/B2 issue S3 access keys you use the same way.
* **GCS:** Application Default Credentials (workload identity / `GOOGLE_APPLICATION_CREDENTIALS`), or a service-account JSON supplied as a secret.

### Endpoint and addressing notes

* **Endpoint required:** R2 (`https://<account_id>.r2.cloudflarestorage.com`), Tigris, and Wasabi have no usable default — set `MVS_OBJECT_STORE_ENDPOINT` or MVS fails fast with a clear message rather than silently hitting AWS.
* **Path-style addressing** is applied automatically for B2, MinIO, Ceph, and LocalStack (they only serve path-style); AWS/R2/Tigris/Wasabi use virtual-hosted style.

### Shard settings

Set these on the MVS shard, and point them at the same bucket as the variables above.

**With the Helm chart**, set `mvs.objectStore` in your values file. The chart writes the shard variables for you:

```yaml theme={null}
mvs:
  objectStore:
    backend: s3                          # "s3" or "gcs"
    bucket: my-mvs-data
    endpoint: https://minio.internal:9000  # S3-compatible stores only
    region: us-east-1                    # optional
    secretRef: mvs-object-store-creds    # Secret with the access keys
```

The chart accepts only `s3` and `gcs`. Use `s3` for MinIO, R2, and every other S3-compatible store. Keep credentials out of the values file. Put them in the Secret that `secretRef` names, as `MVS_S3_ACCESS_KEY_ID` and `MVS_S3_SECRET_ACCESS_KEY` (or `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`).

**Without the chart**, set these on each shard container:

| Variable | Backend | Default | Description |
| - | - | - | - |
| `MVS_STORE_BACKEND` | all | `none` | `s3` or `gcs`. With `none`, the shard starts empty and persists nothing. |
| `MVS_S3_BUCKET` | `s3` | `mvs-snapshots` | Bucket name. |
| `MVS_S3_ENDPOINT` | `s3` | (unset) | Endpoint for S3-compatible stores. |
| `MVS_S3_REGION` | `s3` | `us-east-1` | Region. |
| `MVS_S3_PREFIX` | `s3` | `mvs` | Key prefix. |
| `MVS_S3_ACCESS_KEY_ID` / `MVS_S3_SECRET_ACCESS_KEY` | `s3` | (unset) | Access keys. Falls back to `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`. |
| `MVS_GCS_BUCKET` | `gcs` | `mvs-snapshots` | Bucket name. Credentials come from Application Default Credentials. |

> [!WARNING]
>
> Set `MVS_STORE_BACKEND` explicitly. If you leave it unset, the shard boots without an error, serves an empty index, and writes no snapshots.

## Local and parallel filesystems (private beta)

> [!NOTE]
>
> MVS can store its data on a POSIX filesystem, such as local NVMe, NFS, or Lustre. This backend is in private beta and opt-in. To enable it for your deployment, [contact us](https://mixpeek.com/contact).

## Encryption at rest

Set `MVS_ENCRYPTION_KEY` (base64-encoded 32 bytes) to transparently encrypt every object with **AES-256-GCM**. The object's storage key is used as additional authenticated data (AAD), binding each ciphertext to its path. Migration needs no backfill: existing unencrypted objects stay readable while new writes are encrypted, so you can enable it on a populated bucket without a backfill.

## Examples

```bash Amazon S3 theme={null}
MVS_OBJECT_STORE_PROVIDER=s3
MVS_BUCKET=my-mvs-data
MVS_REGION=us-east-1
# credentials via attached IAM role (recommended) or AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
```

```bash Cloudflare R2 theme={null}
MVS_OBJECT_STORE_PROVIDER=r2
MVS_BUCKET=my-mvs-data
MVS_OBJECT_STORE_ENDPOINT=https://<account_id>.r2.cloudflarestorage.com
AWS_ACCESS_KEY_ID=<r2_access_key>
AWS_SECRET_ACCESS_KEY=<r2_secret_key>
```

```bash Google Cloud Storage theme={null}
MVS_OBJECT_STORE_PROVIDER=gcs
MVS_BUCKET=my-mvs-data
# credentials via workload identity / GOOGLE_APPLICATION_CREDENTIALS
```

```bash MinIO (self-hosted) theme={null}
MVS_OBJECT_STORE_PROVIDER=minio
MVS_BUCKET=my-mvs-data
MVS_OBJECT_STORE_ENDPOINT=https://minio.internal:9000
AWS_ACCESS_KEY_ID=<minio_access_key>
AWS_SECRET_ACCESS_KEY=<minio_secret_key>
```

## Write extraction outputs to your bucket

A bucket can name a `destination`: a storage connection you own with write access enabled. Extraction outputs and derived assets (segments, thumbnails, transcodes, renders) are then written under your prefix, each object carrying its lineage as object metadata, and Mixpeek's storage keeps no copy. This works on every deployment, including the shared plane.

| Field | Type | What it does |
| - | - | - |
| `destination.connection_id` | string | A storage connection you own (S3-compatible, including Cloudflare R2 through its `endpoint_url`, or GCS) with `write_enabled: true` |
| `destination.prefix` | string | Key prefix inside the connection's bucket, for example `mixpeek-outputs/`. Empty writes at the root; a trailing slash is added if you omit it |

Enable writes on the connection first:

```bash theme={null}
curl -X PATCH https://api.mixpeek.com/v1/organizations/connections/$CONNECTION_ID \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"write_enabled": true}'
```

Then bind it on the bucket, on create or update:

```bash theme={null}
curl -X PATCH https://api.mixpeek.com/v1/buckets/$BUCKET_ID \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-Namespace: $NAMESPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{"destination": {"connection_id": "'$CONNECTION_ID'", "prefix": "mixpeek-outputs/"}}'
```

A connection without write access is refused naming the connection.

## Related

* [Object Storage Integrations](https://docs.mixpeek.com/docs/integrations/object-storage/overview.md) — connect a bucket as an ingestion source
* [Single-Tenant Deployments](https://docs.mixpeek.com/docs/resources/single-tenant.md) — fully isolated data plane with a dedicated bucket
* [Vector Store Overview](https://docs.mixpeek.com/docs/vector-store/overview.md) — using MVS as a standalone vector store


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.