payloadcms / payloadcms/payload
s3Storage plugin uploads to S3 but admin panel and API sPAYPUB-290till serve local URLs despite disableLocalStorage: true
Nobody has claimed this yet.
- 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
- Set up a new Payload CMS project using the latest version.
- Configure PostgreSQL database using Supabase (or any Postgres instance).
- 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
-
Use the following collection config for media with
disableLocalStorage: trueandadminThumbnailset to a custom URL (for testing). -
Use the s3Storage plugin configured with prefix: 'images' for the media collection.
-
Upload media files via the admin panel.
-
Observe that uploads correctly go to S3, but the file URLs served are still pointing to local server URLs instead of S3 URLs.
-
The adminThumbnail function is ignored; thumbnails still show local URLs.
-
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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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