
# Buckets Overview

Buckets are named containers for uploaded files. Each bucket carries its own size limit, allowed MIME types, public/private visibility, and access permissions. Tables reference buckets through [attachment fields](/en/docs/attachment-fields), [forms](/en/docs/form-file-uploads) write files into them, and the REST API exposes upload, download, signed-URL, and image-transform endpoints.

Two concerns are deliberately separated:

- **Where files are stored** — the storage _backend_ — is operator-controlled via environment variables (`STORAGE_PROVIDER` and friends). It never appears in the app schema.
- **How files are organized** — the _buckets_ — is application configuration declared in the top-level `buckets[]` array of your config.

```yaml
buckets:
  - name: avatars
    public: true
    maxFileSize: 2097152
    allowedMimeTypes: [image/jpeg, image/png, image/webp]
    permissions:
      upload: authenticated
      download: all
      delete: [admin]
```

When `buckets` is omitted entirely, Sovrium provisions an implicit `default` bucket (`public: false`, standard permission defaults).

## Storage Backends

The backend is chosen at deploy time with `STORAGE_PROVIDER`. All three backends support the full file-operations, signed-URL, and image-transform surface.

| Backend            | `STORAGE_PROVIDER`                     | Best for                                    | Scalability    | Native presigned URLs           |
| ------------------ | -------------------------------------- | ------------------------------------------- | -------------- | ------------------------------- |
| Local filesystem   | `local` (default)                      | Development, single-node, self-hosted       | Disk-bound     | No (Sovrium signs internally)   |
| S3 / S3-compatible | `s3`                                   | Production, scale-out                       | Unlimited      | Yes (delegated to the provider) |
| MinIO              | `s3` + `STORAGE_FORCE_PATH_STYLE=true` | Self-hosted S3-compatible object store      | Unlimited      | Yes                             |
| PostgreSQL `bytea` | `bytea`                                | Small files, simple single-database deploys | Database-bound | No (Sovrium signs internally)   |

:::callout
**Frugal by default.** The default backend is `local` — zero external dependencies, mirroring Sovrium's SQLite-default database posture. Opt _out_ to S3 only when you need scale-out or multi-node deployments. See [Ecoconception](/en/docs/ecoconception).
:::

### Backend Environment Variables

| Variable                   | Required | Default     | Purpose                                                                  |
| -------------------------- | -------- | ----------- | ------------------------------------------------------------------------ |
| `STORAGE_PROVIDER`         | No       | `local`     | Storage backend: `s3`, `local`, or `bytea`.                              |
| `STORAGE_ENDPOINT`         | S3 only  | —           | S3-compatible endpoint URL.                                              |
| `STORAGE_BUCKET`           | S3 only  | —           | Underlying S3 bucket name (the host object store, not a Sovrium bucket). |
| `STORAGE_REGION`           | S3 only  | `us-east-1` | AWS region.                                                              |
| `STORAGE_ACCESS_KEY`       | S3 only  | —           | S3 access key ID.                                                        |
| `STORAGE_SECRET_KEY`       | S3 only  | —           | S3 secret access key.                                                    |
| `STORAGE_FORCE_PATH_STYLE` | No       | `false`     | Use path-style URLs (required for MinIO).                                |

:::callout
**Sovrium buckets are path prefixes, not S3 buckets.** Every bucket you declare in `buckets[]` maps to a path prefix inside the single host bucket configured by `STORAGE_BUCKET` (e.g. `avatars/`, `documents/`). One S3 bucket holds all your Sovrium buckets.
:::

See [Environment Variables](/en/docs/env-vars) for the full operator-facing variable reference.

## Bucket Properties

Each entry in the `buckets[]` array accepts the following properties.

| Property           | Description                                                                                                                                                   |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`             | Unique bucket name. Lowercase, alphanumeric, hyphens; must start with a letter; max 63 characters (S3 prefix compatibility). Used as the storage path prefix. |
| `public`           | Boolean. When `true`, files are served without signed URLs. Defaults to `false` (private).                                                                    |
| `maxFileSize`      | Maximum file size in bytes for uploads to this bucket. Overrides the global `STORAGE_MAX_FILE_SIZE`. Must be ≥ 1.                                             |
| `allowedMimeTypes` | Array of allowed MIME types for uploads. Supports wildcards (e.g. `image/*`). When omitted, all types are accepted. Minimum one entry.                        |
| `permissions`      | Per-operation access control. See [Permissions](#permissions) below.                                                                                          |

:::callout
**Name validation is strict.** `Avatars` (uppercase) and `123-bucket` (leading digit) are rejected by `sovrium validate`. Valid examples: `avatars`, `documents`, `public-assets`, `user-uploads`. Duplicate names across the array are also rejected at validation time.
:::

## Permissions

Bucket permissions use the same shared `PermissionValueSchema` format as [table permissions](/en/docs/table-permissions): each operation accepts `all`, `authenticated`, or a list of role names.

| Operation    | Description                              | Default                                     |
| ------------ | ---------------------------------------- | ------------------------------------------- |
| `upload`     | Who can upload files to this bucket.     | `authenticated`                             |
| `download`   | Who can download files from this bucket. | `all` if public, `authenticated` if private |
| `sign`       | Who can generate signed download URLs.   | `authenticated`                             |
| `signUpload` | Who can generate signed upload URLs.     | `[admin]`                                   |
| `delete`     | Who can delete files from this bucket.   | `[admin]`                                   |

Permission values:

- `all` — everyone, including unauthenticated requests.
- `authenticated` — any logged-in user.
- `['admin', 'editor']` — only the listed roles.

```yaml
buckets:
  - name: documents
    maxFileSize: 52428800
    allowedMimeTypes: [application/pdf, text/csv]
    permissions:
      upload: [admin, editor]
      download: authenticated
      sign: authenticated
      signUpload: [admin, editor]
      delete: [admin]
```

When a bucket omits `permissions` entirely, the per-operation defaults above apply — notably, only the `admin` role can generate signed URLs.

## Public vs Private

| Visibility                | Behavior                                                                                                            |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `public: true`            | Files served directly without authentication or signed URLs. Suitable for avatars, logos, marketing assets.         |
| `public: false` (default) | Files require either authentication (matching `download` permission) or a valid [signed URL](/en/docs/signed-urls). |

Operators can additionally expose path prefixes globally via `STORAGE_PUBLIC_PATHS` (see [Signed URLs](/en/docs/signed-urls)).

## Example: Multiple Buckets

A public images bucket alongside a private, role-gated documents bucket.

```yaml
buckets:
  - name: avatars
    public: true
    maxFileSize: 2097152
    allowedMimeTypes: [image/*]
    permissions:
      upload: authenticated
      download: all
      delete: [admin]

  - name: documents
    maxFileSize: 52428800
    allowedMimeTypes: [application/pdf]
    permissions:
      upload: [admin, editor]
      download: authenticated
      sign: authenticated
      signUpload: [admin, editor]
      delete: [admin]
```

## Related Pages

- [File Operations](/en/docs/file-operations) — upload, download, list, and delete endpoints.
- [Signed URLs](/en/docs/signed-urls) — time-limited access to private files.
- [Image Transforms](/en/docs/image-transforms) — on-the-fly resize, crop, and format conversion.
- [Attachment Fields](/en/docs/attachment-fields) — storing files against table records.
- [Form File Uploads](/en/docs/form-file-uploads) — accepting files through forms.
- [Environment Variables](/en/docs/env-vars) — operator-facing backend configuration.
