Skip to content

Neon Object Storage Integration ​

Neon Object Storage is S3-compatible object storage that comes with every Neon project and is branched along with the database. Sveltia CMS supports it as a media storage backend through its S3-compatible API, with direct browser-to-storage uploads using AWS Signature Version 4 — no backend proxy is required.

Requirements ​

  • A Neon project in a region that offers Object Storage: aws-us-east-1, aws-us-east-2, aws-eu-central-1 or aws-ap-southeast-1.
  • A bucket on the branch you want to use, with public_read access or a CDN in front of it (see Public Read Access below).
  • A storage access key pair (see Credentials below).

CSP ​

If your site uses a Content Security Policy (CSP), you need to allow your branch’s storage endpoint. See Content Security Policy below for details.

Setup ​

Endpoint ​

Each Neon branch has its own storage endpoint, e.g. https://br-cool-darkness-a1b2c3d4.storage.c-1.us-east-2.aws.neon.tech. Find it as AWS_ENDPOINT_URL_S3 under Neon Console > [project] > Connect > Storage, and set it as endpoint in your config.

The endpoint can’t be built from the project or branch ID, because its hostname also includes a cell ID (c-1 above). Copy it as is.

Sveltia CMS only accepts an HTTPS endpoint on a Neon storage hostname (*.storage.*.aws.neon.tech). Any other URL is ignored, and the storage won’t be available. This keeps the signed requests, which carry your credentials, from being sent to another host by mistake.

The region is read from the endpoint’s hostname (us-east-2 above), so you don’t need to set region.

Credentials ​

Create a storage access key pair in one of these ways:

  • In Neon Console > [project] > Connect > Storage.
  • With the Neon CLI: neon credentials create --scope storage:read --scope storage:write.

See Authentication in the Neon documentation for details.

The resulting Access Key ID (nak_live_…) goes in access_key_id in your config. The Secret Access Key (nsk_live_…) is entered by users in the CMS UI when they access the media library for the first time — it is never stored in config.

TIP

Use a key pair with both the storage:read and storage:write scopes, so that uploads, renames and deletions work.

Public Read Access ​

Neon sets access per bucket, as either private or public_read, in the Neon Console, CLI or API.

A public_read bucket serves its files anonymously at {endpoint}/{bucket}/{key}, which is the URL Sveltia CMS uses for asset previews and stores in your entries by default.

A private bucket returns an error for anonymous requests, so preview images fail to load and the stored URLs don’t work on your site. To use a private bucket, put a CDN in front of it and set its URL as public_url. See CDN / Custom Domain below.

CORS ​

No CORS configuration is needed. Neon Object Storage allows cross-origin requests from any origin by default, so listing, uploading, renaming and deleting from the browser work out of the box.

Configuration ​

Here’s an example configuration for Neon Object Storage:

yaml
media_libraries:
  neon_object_storage:
    access_key_id: nak_live_0123456789abcdef0123456789abcdef
    bucket: media
    endpoint: https://br-cool-darkness-a1b2c3d4.storage.c-1.us-east-2.aws.neon.tech
    prefix: cms-uploads/ # Optional
toml
[media_libraries.neon_object_storage]
access_key_id = "nak_live_0123456789abcdef0123456789abcdef"
bucket = "media"
endpoint = "https://br-cool-darkness-a1b2c3d4.storage.c-1.us-east-2.aws.neon.tech"
prefix = "cms-uploads/" # Optional
json
{
  "media_libraries": {
    "neon_object_storage": {
      "access_key_id": "nak_live_0123456789abcdef0123456789abcdef",
      "bucket": "media",
      "endpoint": "https://br-cool-darkness-a1b2c3d4.storage.c-1.us-east-2.aws.neon.tech",
      "prefix": "cms-uploads/"
    }
  }
}
js
{
  media_libraries: {
    neon_object_storage: {
      access_key_id: 'nak_live_0123456789abcdef0123456789abcdef',
      bucket: 'media',
      endpoint: 'https://br-cool-darkness-a1b2c3d4.storage.c-1.us-east-2.aws.neon.tech',
      prefix: 'cms-uploads/', // 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 ​

PropertyRequiredDescription
access_key_idYesNeon storage Access Key ID, e.g. nak_live_…. Safe to store in config.
bucketYesThe bucket name.
endpointYesThe branch’s storage endpoint (AWS_ENDPOINT_URL_S3), e.g. https://br-cool-darkness-a1b2c3d4.storage.c-1.us-east-2.aws.neon.tech. See Endpoint above.
regionNoThe region used to sign requests. Defaults to the region in the endpoint’s hostname, e.g. us-east-2. There is normally no reason to set it.
prefixNoPath prefix within the bucket, e.g. uploads/. A trailing slash is added if missing.
public_urlNoCDN or custom domain URL for asset previews. Required for a private bucket. See CDN / Custom Domain below.

CDN / Custom Domain ​

By default, asset URLs use the branch endpoint: {endpoint}/{bucket}/{key}. To serve assets through a CDN or a custom domain in front of the bucket, set public_url to its URL:

yaml
public_url: 'https://cdn.example.com'

Asset URLs are then constructed as {public_url}/{key} (using the full object key, including any prefix).

Content Security Policy ​

API calls (list, upload, rename, delete) go to the branch endpoint, which also serves the assets by default:

connect-src https://br-cool-darkness-a1b2c3d4.storage.c-1.us-east-2.aws.neon.tech;
img-src     https://br-cool-darkness-a1b2c3d4.storage.c-1.us-east-2.aws.neon.tech;

If using a CDN or custom domain via public_url:

connect-src https://br-cool-darkness-a1b2c3d4.storage.c-1.us-east-2.aws.neon.tech
            https://cdn.example.com;
img-src     https://cdn.example.com;

Replace the endpoint and domain with your own.

The asset host must be in connect-src because the Download and Copy buttons and the text preview in the Asset Library fetch the file from its public URL. For the same reason, a CDN or custom domain must also send CORS headers that allow the CMS origin. Otherwise, downloads fail.

See the CSP documentation for more details.

Neon Object Storage-Specific Notes ​

Branches ​

Object Storage is branched along with the database, and each branch has its own endpoint. The CMS uses the branch whose endpoint is in your config, so files uploaded through the CMS go to that branch only.

The stored asset URLs include the endpoint, so they keep pointing to that branch even if you later change the config to another branch.

No Per-Object ACLs ​

Neon Object Storage doesn’t implement the x-amz-acl header for per-object access control. Access is set per bucket instead (see Public Read Access above). Sveltia CMS doesn’t send the header to Neon.

Accessing the Storage ​

There are two ways to use Neon Object Storage in Sveltia CMS:

File and Image Fields ​

When editing content entries, users can use File and Image fields to upload and select media on Neon Object Storage directly within the entry editor. After entering the Secret Access Key in the CMS UI when prompted, users can upload new media to your bucket or select existing media.

Asset Library ​

Neon Object Storage also appears under External Locations in the 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:

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