🚀 Feature Request: Ability to emulate a public R2 bucket when developing locally with Wrangler 3 #13325
Replies: 29 comments
-
|
I'm also curious about AWS features in this scenario - is it implied by this issue that there would be a local S3 API available for buckets as well? Or would that be a separate feature? |
Beta Was this translation helpful? Give feedback.
-
|
This sounds good. +1 on an actual s3 api to use on local (unless i'm missing something) |
Beta Was this translation helpful? Give feedback.
-
|
But wramgler does still emulate R2 locally or what do I miss here? How is accessing the files via the local file system related to an emulation? |
Beta Was this translation helpful? Give feedback.
-
|
Ok, now I get it, apologies for the double post. You want in a second step to serve those files and not only emulate api calls to the bucket. Valid requirement. So there's nothing in wrangler doing that serving part? |
Beta Was this translation helpful? Give feedback.
-
|
Since it was removed from the Project, does it mean this is no longer considered? Having something like |
Beta Was this translation helpful? Give feedback.
-
|
I think what we're all looking for here is the localhost version of the public bucket URL: |
Beta Was this translation helpful? Give feedback.
-
|
Anyone from cloudflare aware of this or working on it? |
Beta Was this translation helpful? Give feedback.
-
|
+1! |
Beta Was this translation helpful? Give feedback.
-
|
would appreciate as well |
Beta Was this translation helpful? Give feedback.
-
|
+1 this would be handy |
Beta Was this translation helpful? Give feedback.
-
|
This would be super helpful |
Beta Was this translation helpful? Give feedback.
-
|
+1 yes please |
Beta Was this translation helpful? Give feedback.
-
|
Does anybody know if they are working on it? |
Beta Was this translation helpful? Give feedback.
-
|
I created a workaround little server using Hono and Bun to serve images from a local Cloudflare R2. Here is the repo : |
Beta Was this translation helpful? Give feedback.
-
|
Nice one @emilienbidet , thanks, will try it out this week! |
Beta Was this translation helpful? Give feedback.
-
fantastic! very helpful |
Beta Was this translation helpful? Give feedback.
-
|
Alternative way: If you navigate to http://localhost:8788/r2/random-file.png:
PS: http://localhost:8788 is a local port of wrangler dev server export default {
async fetch(req, env, ctx) {
try {
const url = new URL(req.url);
if (url.pathname.startsWith('/r2/')) {
// Local R2 storage
const [path, key] = url.pathname.split('/r2/')
console.log("Local r2: ", {path, key});
const file = await env.R2.get(key)
const headers = new Headers();
headers.append('cache-control', 'immutable, no-transform, max-age=31536000');
headers.append('etag', file.httpEtag);
headers.append('date', file.uploaded.toUTCString());
return new Response(file.body, {
headers
})
}
// Otherwise, serve the static assets.
// Without this, the Worker will error and no assets will be served.
return env.ASSETS.fetch(req);
} catch (ex) {
console.error('Worker ex: ', ex)
return new Response("Internal server error", { status: 500 })
}
},
} |
Beta Was this translation helpful? Give feedback.
-
|
@serikshaikamalov that's awesome, just tried it out. Here's the Hono version: app.get('/r2/*', async (c) => {
const key = c.req.path.substring('/r2/'.length)
console.log("Local r2 key: ", key)
const file = await c.env.R2.get(key)
if (!file) throw new APIError("file not found", { status: 404 })
const headers = new Headers()
headers.append('etag', file.httpEtag)
return new Response(file.body, {
headers,
})
}) |
Beta Was this translation helpful? Give feedback.
-
Coool👍 |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
If you're using Nuxt (and have the /**
* `server/api/assets/[filename].get.ts` OR
* `server/routes/assets/[filename].get.ts` (if you don't want the /api endpoint)
**/
export default defineEventHandler(async (event) => {
const { filename } = getRouterParams(event);
if (!filename) {
throw createError({ status: 400, statusMessage: "Bad Request!" });
}
const r2 = event.context.cloudflare.env;
const file = await r2.get(filename);
if (!file) {
throw createError({
status: 404,
statusMessage: "File not found!",
});
}
setHeaders(event, { etag: file.etag });
return file.body;
});Enjoy 💚 |
Beta Was this translation helpful? Give feedback.
-
|
Trying to use Workflows and R2 locally is just plain impossible 👎 |
Beta Was this translation helpful? Give feedback.
-
|
+1 for his feature request. I can't test locally a bucket. A simple browser UI would be also great to simulate file uploads like on the webpage. |
Beta Was this translation helpful? Give feedback.
-
|
Use the code shared above. |
Beta Was this translation helpful? Give feedback.
-
|
If you're using Next.js with opennext
import { getCloudflareContext } from '@opennextjs/cloudflare'
import { NextRequest, NextResponse } from 'next/server'
export async function GET(_: NextRequest, { params }: { params: Promise<{ key: string[] }> }) {
if (process.env.NODE_ENV !== 'development') return new NextResponse('Not Found', { status: 404 })
const { key: keySegments } = await params
const key = keySegments.join('/')
const cloudflare = getCloudflareContext()
try {
const file = await cloudflare.env.R2.get(key)
if (!file) {
return new NextResponse('File not found', { status: 404 })
}
const headers = new Headers()
headers.append('etag', file.httpEtag)
return new NextResponse(file.body, {
headers,
status: 200,
})
} catch (error) {
console.error(`Error fetching key "${key}" from R2:`, error)
return new NextResponse('Internal Server Error', { status: 500 })
}
} |
Beta Was this translation helpful? Give feedback.
-
|
any update from Cloudflare team? This is a very needed feature please consider it. |
Beta Was this translation helpful? Give feedback.
-
|
Hey team - curious if there is a timeline for this? Really enjoying working with your AI tools but lack of ability to access R2 locally is causing some stress that may result in having to migrate away. Thanks! |
Beta Was this translation helpful? Give feedback.
-
|
Weird they don't have this feature when working with R2 locally? |
Beta Was this translation helpful? Give feedback.
-
|
I'd like to take a crack at this. Here's my proposed approach: Goal: Serve R2 objects via plain HTTP URL during Approach: Add a new HTTP-serving worker service within the R2 plugin (
Configuration: A new option in {
"r2_buckets": [{
"binding": "MY_BUCKET",
"bucket_name": "my-bucket",
"local_public_port": 8788 // new option
}]
}Pattern: Following the existing assets plugin ( The infrastructure already exists (R2 simulation, metadata, range support in Happy to discuss before writing code. Would this direction work? |
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
-
Describe the solution
Under Wrangler 2, when running locally any files you'd upload to a "local" R2 bucket would be saved in a directory with the exact filename you gave it at upload time, which meant you could very easily emulate a public R2 bucket by pointing
serveat it or something similar.Unfortunately this approach doesn't work anymore with Wranger 3 (or I guess Miniflare now?) because the filenames are all hashes now and there's an SQLite database involved as well, and as far as I can tell there's no ability to emulate a public bucket except by actually having a public bucket for real in Cloudflare.
It'd be great to have an extra flag when running
wrangler dev, maybe something similar to--assets, that could specify that the R2 bucket should act as though it was public.Beta Was this translation helpful? Give feedback.
All reactions