---
url: /en/docs/media/digitalocean-spaces.md
description: >-
  Use DigitalOcean Spaces as an external media storage provider in Sveltia CMS
  for simple, S3-compatible object storage with a built-in CDN.
---

# DigitalOcean Spaces Integration

[DigitalOcean Spaces](https://www.digitalocean.com/products/spaces) is an S3-compatible object storage service with a built-in CDN. Sveltia CMS supports Spaces as a media storage backend with direct browser-to-Spaces uploads using AWS Signature Version 4 — no backend proxy is required.

## Requirements

* A DigitalOcean account with a Space created.
* A Spaces Access Key (see [Credentials](#credentials) below).

### CSP

If your site uses a Content Security Policy (CSP), you need to allow the Spaces endpoint. See [Content Security Policy](#content-security-policy) below for details.

## Setup

### Credentials

Spaces uses its own key pair, separate from DigitalOcean personal access tokens. Generate one via **DigitalOcean Control Panel > API > Spaces Keys**.

Note: each key pair covers all Spaces in your account — there is no per-bucket scoping.

The resulting **Access Key** goes in `access_key_id` in your config. The **Secret Key** is entered by users in the CMS UI when they access the media library for the first time — it is never stored in config.

### Public Read Access

Asset preview and download URLs are unsigned direct storage URLs, so objects must be publicly readable. Files in a Space are private by default. The Space’s file listing setting only controls whether anyone can list them, not whether they can be read.

Sveltia CMS therefore gives every file it uploads or renames, and every folder it creates, the `public-read` ACL. No further setup is needed, and the file listing can stay private.

Files uploaded by other means, such as the control panel, stay private unless you set their permissions to **Public**. Their previews won’t load in the CMS until you do.

### CORS

Configure via **DigitalOcean Control Panel > Spaces > Select bucket > Settings > CORS**. CORS is required because Sveltia CMS sends custom AWS Signature v4 headers that trigger a preflight request.

```json
[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET", "PUT", "DELETE", "HEAD"],
    "AllowedOrigins": ["https://your-cms-domain.com"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3000
  }
]
```

The `DELETE` method and the wildcard `AllowedHeaders` are needed to delete and rename files from the [Asset Library](/en/docs/ui/asset-library). If you configured CORS before these operations became available, add them to your existing policy. Otherwise, the browser will block those requests during the preflight check.

## Configuration

Here’s an example configuration for DigitalOcean Spaces:

::: code-group

```yaml [YAML]
media_libraries:
  digitalocean_spaces:
    access_key_id: ABCD1234EFGH5678IJKL
    bucket: my-space
    region: nyc3
    prefix: cms-uploads/ # Optional
    public_url: https://my-space.nyc3.cdn.digitaloceanspaces.com # Optional, see CDN Endpoint below
```

```toml [TOML]
[media_libraries.digitalocean_spaces]
access_key_id = "ABCD1234EFGH5678IJKL"
bucket = "my-space"
region = "nyc3"
prefix = "cms-uploads/"
public_url = "https://my-space.nyc3.cdn.digitaloceanspaces.com"
```

```json [JSON]
{
  "media_libraries": {
    "digitalocean_spaces": {
      "access_key_id": "ABCD1234EFGH5678IJKL",
      "bucket": "my-space",
      "region": "nyc3",
      "prefix": "cms-uploads/",
      "public_url": "https://my-space.nyc3.cdn.digitaloceanspaces.com"
    }
  }
}
```

```js [JavaScript]
{
  media_libraries: {
    digitalocean_spaces: {
      access_key_id: 'ABCD1234EFGH5678IJKL',
      bucket: 'my-space',
      region: 'nyc3',
      prefix: 'cms-uploads/', // Optional
      public_url: 'https://my-space.nyc3.cdn.digitaloceanspaces.com', // Optional
    },
  },
}
```

:::

::: warning

Do not write your Secret Access Key in the configuration file, as it should be kept confidential and not exposed in client-side code. Users will be prompted to enter the key when they use the storage for the first time. It’s then stored securely in the browser’s local storage.

:::

### Configuration Properties

| Property | Required | Description |
| --- | --- | --- |
| `access_key_id` | Yes | Spaces Access Key. Safe to store in config. |
| `bucket` | Yes | The Space name. |
| `region` | Yes | Spaces region, e.g. `nyc3`, `sfo2`, `ams3`, `sgp1`, `fra1`. |
| `prefix` | No | Path prefix within the bucket, e.g. `uploads/`. A trailing slash is added if missing. |
| `public_url` | No | CDN or custom subdomain URL for asset previews. See [CDN Endpoint](#cdn-endpoint) below. |

## CDN Endpoint

DigitalOcean Spaces has an optional built-in CDN. Once enabled, the default CDN endpoint is `https://{bucket}.{region}.cdn.digitaloceanspaces.com`. You can also configure a custom subdomain — see the [Spaces CDN custom endpoint guide](https://docs.digitalocean.com/products/spaces/how-to/customize-cdn-endpoint/).

By default, asset URLs use the virtual-hosted storage endpoint (`https://{bucket}.{region}.digitaloceanspaces.com/{key}`). To use the CDN instead, set `public_url` to the CDN or custom subdomain URL:

```yaml
public_url: 'https://my-space.nyc3.cdn.digitaloceanspaces.com'
# or with a custom subdomain:
public_url: 'https://images.example.com'
```

::: warning

Do **not** set `public_url` to the CDN URL and rely on it for API operations. The CDN endpoint does not support the S3 ListObjects API, so browsing the asset library would stop working. The storage endpoint is always used for listing and uploading. Only the asset URLs shown in the CMS change.

:::

## Content Security Policy

API calls (list, upload) go to `https://{region}.digitaloceanspaces.com`. Asset URLs use `https://{bucket}.{region}.digitaloceanspaces.com` by default:

```
connect-src https://nyc3.digitaloceanspaces.com
            https://my-space.nyc3.digitaloceanspaces.com;
img-src     https://my-space.nyc3.digitaloceanspaces.com;
```

If using the CDN via `public_url`:

```
connect-src https://nyc3.digitaloceanspaces.com
            https://my-space.nyc3.cdn.digitaloceanspaces.com;
img-src     https://my-space.nyc3.cdn.digitaloceanspaces.com;
```

Replace `nyc3` and `my-space` with your actual region and bucket name. If you use a custom subdomain, such as `https://images.example.com`, allow it in place of the CDN endpoint.

The asset host must be in `connect-src` because the Download and Copy buttons and the text preview in the [Asset Library](/en/docs/ui/asset-library) fetch the file from its public URL. For the same reason, a CDN or custom subdomain must also send CORS headers that allow the CMS origin. Otherwise, downloads fail.

See the [CSP documentation](/en/docs/security#setting-up-content-security-policy) for more details.

## Accessing the Storage

There are two ways to use DigitalOcean Spaces in Sveltia CMS:

### File and Image Fields

When editing content entries, users can use [File](/en/docs/fields/file) and [Image](/en/docs/fields/image) fields to upload and select media on DigitalOcean Spaces directly within the entry editor. After entering the Secret Access Key in the CMS UI when prompted, users can upload new media directly to Spaces or select existing media from the bucket.

When uploading media, files will be stored in the Spaces bucket, and the CMS can take advantage of Spaces’ capabilities directly from the CMS. You can also select existing media from your Spaces storage.

### Asset Library

DigitalOcean Spaces also appears under **External Locations** in the [Asset Library](/en/docs/ui/asset-library). There, users can browse, search, sort and filter the files in your bucket, and upload, rename, replace, download or delete them without leaving the CMS.

The files and folders are browsed [folder by folder](/en/docs/ui/asset-library#folders-on-external-locations):

* Subfolders are listed ahead of the files.
* Uploads go to the folder being viewed.
* Folders can be created, renamed and deleted.
