Hello, I'm genuinely at a loss and really need some guidance. I'm pretty sure most of my issues are from using the Starter Website Template instead of building my site up from scratch, but when I first started this project figured skipping some of the tedious steps would've been worth my time. I've gotten the site to the point where I want to get images working properly. Right now the site is up and I can see the content, but I can't fetch images from my Cloudflare R2.
I'm using the S3 Plugin as I've seen mentioned in tutorials and it is properly uploading the images from the Admin Panel. The trouble comes when the site tries to find the appropriate images, it's still trying to find the images in local storage. I'm using Vercel from my deployments, so I need to figure out where to make any changes to the Template code to allow it to find me R2 and ignore local storage properly.
Apologies if this is a duplicate issue or in the wrong sectio. Thank you in advance for any help.
Hey
@175753360740319233can you clarify, are you using the AWS S3 plugin or the Cloudflare R2 plugin?
The S3 plugin.
Most of the write-ups or tutorials I came across suggested using it over the R2 plugin.
Ok, just wanted to make sure as you mentioned both in your message
so you have an Amazon S3 bucket and all your credentials in your env file?
S3_BUCKET = the name of the bucket you created in AWS
S3_ACCESS_KEY_ID = from AWS IAM → Users → Security credentials → Access keys
S3_SECRET_ACCESS_KEY = shown once when creating the access key, can't be retrieved after
S3_REGION = wherever your bucket was created (us-east-1, eu-west-1, etc.)My bucket is an R2 on Cloudfare, but yes all my credentials are in my env file and I have the plugin configured using them.
I'll admit some of the guides and write-ups I used were a little older, so if the R2 plugin is more mature than mentioned in those articles/videos I can give it a try.
That might explain the issue. If you are using Cloudflare then you need to use the R2 plugin. They are not interchangeable. S3 for AWS R2 for Cloudflare. Even if you have your env variables in there, if you don't have it setup properly your local instance is just going to default to uploading media to /api/media, which makes sense why you don't see your images once deployed
Ok, that's a little confusing then because the Payload documentation for the [Storage Adapters](
https://payloadcms.com/docs/upload/storage-adapters) says to use the S3 plugin because Cloudflare supports the S3 API and the R2 Plugin is still marked as "in Beta."
Ohhh
you are right
my mistake!
So it does look like cloudflare exposes an S3-compatible HTTP endpoint for R2—meaning any S3 client can talk to it
So I think what you'd need to update for your ENV variables is:
S3_REGION=auto
S3_ENDPOINT=https://<account-id>.r2.cloudflarestorage.comThat is currently how they are set.
s3Storage({
enabled: true,
clientUploads: true,
collections:{
media: {
disableLocalStorage: true
},
},
//@ts-ignore
bucket: process.env.R2_BUCKET,
config: {
credentials: {
//@ts-ignore
accessKeyId: process.env.R2_ACCESS_KEY_ID,
//@ts-ignore
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
},
region: 'auto',
endpoint: `https://${process.env.R2_ENDPOINT}`,
forcePathStyle: true,
},
})and you have each of those envs defined on your Vercel project? I know you mentioned env above, just double checking all the simple things first
Yes, both the Environment page on the Vercel dashboard and my local .env share the same variable names and values.
Ok, if you go to a media item in payload and hover the name what does the URL look like
Currently it seems my admin panel is down in production, when I spin it up on local host the url is
localhost:3000/api/media/file/<image-file>aha
Did you upload those files
beforeyou enabled the s3 plugin?
also what images specifically are not being found in production?
It is possible, I've been working on this project for a couple months now. I can confirm the images are in the R2 Bucket, however.
Currently no images are being found in prod
Ok two things:
1. Is your bucket set to private or public right now? If private, you need to set it to public-this is what gives you the *.r2.dev URL to use as R2_PUBLIC_URL
2. Add this into your media config under disableLLocalStorage
generateFileURL: ({ filename }) =>
https://${process.env.R2_PUBLIC_URL}/${filename},
Public access is currently disabled, let me change it and I'll check back
Cloudflare is providing me a warning that this link is not intended for production use
Cloudflare suggests not using the Public Dev URL and rather using the Custom Domains feature to properly link the website and the R2, would the Custom Domain take the place of the *.r2.dev URL?
Or would I use the S3 API url provided by Cloudflare?
Yes (to your first question) so it should look like this:
s3Storage({
enabled: true,
clientUploads: true,
collections: {
media: {
disableLocalStorage: true,
generateFileURL: ({ filename }) =>
`https://${process.env.R2_PUBLIC_URL}/${filename}`,
},
},
bucket: process.env.R2_BUCKET || '',
config: {
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID || '',
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY || '',
},
region: 'auto',
endpoint: `https://${process.env.R2_ENDPOINT}`,
forcePathStyle: true,
},
})with these ENVs:
R2_BUCKET=my-bucket
R2_ACCESS_KEY_ID=...
R2_SECRET_ACCESS_KEY=...
R2_ENDPOINT=<account-id>.r2.cloudflarestorage.com
R2_PUBLIC_URL=media.theirdomain.comOk, then I think the Media issue should be resolved. I think I'll have to open a new issue, however as my local deployment is showing up without styling and when I pushed my changes to my preview branch, Vercel logs are showing a build error:
Failed to compile.
Type error: Type 'typeof import("/vercel/path0/src/app/(frontend)/next/preview/route")' does not satisfy the constraint 'RouteHandlerConfig<"/next/preview">'.
Types of property 'GET' are incompatible.
Type '(req: { cookies: { get: (name: string) => { value: string; }; }; } & Request) => Promise<Response>' is not assignable to type '(request: NextRequest, context: { params: Promise<{}>; }) => void | Response | Promise<void | Response>'.
Types of parameters 'req' and 'request' are incompatible.
Type 'NextRequest' is not assignable to type '{ cookies: { get: (name: string) => { value: string; }; }; } & Request'.
Type 'NextRequest' is not assignable to type '{ cookies: { get: (name: string) => { value: string; }; }; }'.
The types returned by 'cookies.get(...)' are incompatible between these types.
Type 'RequestCookie | undefined' is not assignable to type '{ value: string; }'.
Type 'undefined' is not assignable to type '{ value: string; }'.
Next.js build worker exited with code: 1 and signal: null
ELIFECYCLE Command failed with exit code 1.
Error: Command "pnpm run build" exited with 1Glad we got that sorted out! If this pops up again, let me know!
Sure thing, I've also opened a new post with the build error I'm experiencing if you have the time to look.
Star
Discord
online
Get dedicated engineering support directly from the Payload team.