payloadcms / payloadcms/payload

s3Storage plugin uploads to S3 but admin panel and API sPAYPUB-290till serve local URLs despite disableLocalStorage: true

Open
#12,659 12 comments 7 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

plugin: storage-* stale
Dominant language
TypeScript
Stars
44.8k
Forks
4.2k
Avg merge
2d 21h
Merged PRs (30d)
53

Description

Describe the Bug

I'm using Payload CMS with the official s3Storage plugin configured for my media collection. I set disableLocalStorage: true to prevent saving files locally, expecting all media URLs (in admin panel and API) to point to S3-hosted files.

Media collection config:

export const Media: CollectionConfig = {
  slug: 'media',
  access: {
    read: () => true,
  },
  upload: {
    disableLocalStorage: true,
  },
  fields: [],
}

My Payload config with the S3 plugin:

plugins: [
  s3Storage({
    collections: {
      media: {
        prefix: 'images',
      },
    },
    bucket,
    config: {
      region,
      credentials: {
        accessKeyId,
        secretAccessKey,
      },
    },
  }),
],

payloadCloudPlugin is deliberately removed... it didnt upload the files to S3 with it

Expected:

Uploaded files saved only in S3 (under the configured prefix).
Admin panel and API file URLs point directly to S3.
No local URLs or file paths are referenced.

Actual:

Files successfully upload to S3.
Admin panel thumbnails and API file URLs still point to local /api/media/file/... paths.
Local files are kept somewhere since they still load, both locally and if i deploy it to vercel

Additional details:

Setting a custom adminThumbnail does not override the URLs shown. ( Thought this as a workaround-> didnt work)
Is this expected behavior, or is there an issue in how Payload integrates the S3 plugin with upload URL generation?

Link to the code that reproduces this issue

"N/A - cannot provide a public reproduction link at this time

Reproduction Steps
  1. Set up a new Payload CMS project using the latest version.
  2. Configure PostgreSQL database using Supabase (or any Postgres instance).
  3. Configure AWS S3 storage plugin with these minimal environment variables set:

env

S3_BUCKET=your-bucket-name
S3_REGION=your-region
S3_ACCESS_KEY_ID=your-access-key-id
S3_SECRET_ACCESS_KEY=your-secret-access-key
DATABASE_URI=your-supabase-postgres-connection-string
  1. Use the following collection config for media withdisableLocalStorage: trueand adminThumbnail set to a custom URL (for testing).

  2. Use the s3Storage plugin configured with prefix: 'images' for the media collection.

  3. Upload media files via the admin panel.

  4. Observe that uploads correctly go to S3, but the file URLs served are still pointing to local server URLs instead of S3 URLs.

  5. The adminThumbnail function is ignored; thumbnails still show local URLs.

  6. Local files are accessible, but remote S3 files are not linked properly.

Which area(s) are affected? (Select all that apply)

Not sure, plugin: cloud-storage

Environment Info
Binaries:
  Node: 22.15.0
  npm: N/A
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  payload: 3.40.0
  next: 15.3.0
  @payloadcms/db-postgres: 3.40.0
  @payloadcms/email-nodemailer: 3.40.0
  @payloadcms/graphql: 3.40.0
  @payloadcms/next/utilities: 3.40.0
  @payloadcms/payload-cloud: 3.40.0
  @payloadcms/plugin-cloud-storage: 3.40.0
  @payloadcms/richtext-lexical: 3.40.0
  @payloadcms/storage-s3: 3.40.0
  @payloadcms/translations: 3.40.0
  @payloadcms/ui/shared: 3.40.0
  react: 19.1.0
  react-dom: 19.1.0
Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Home
  Available memory (MB): 7858
  Available CPU cores: 8

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the @payloadcms/storage-s3 package and the media collection's upload configuration, especially disableLocalStorage and adminThumbnail. Reproduce the upload using the stated S3 and PostgreSQL setup, then trace how the admin panel and API construct media URLs. Done means uploads remain in S3 and both interfaces use the configured S3 URLs without local paths.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, nextjs, postgresql, typescript
Domain
api, backend, cloud
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.