Coding
PromptBeginner5 minmarkdown
Nano Banana Pro
Agent skill for nano-banana-pro
6
>
Sign in to like and favorite skills
# wrangler.toml [[r2_buckets]] binding = "MY_BUCKET" bucket_name = "my-bucket"
export interface Env { MY_BUCKET: R2Bucket }
// Upload file await env.MY_BUCKET.put("path/to/file.txt", fileBuffer, { httpMetadata: { contentType: "text/plain", cacheControl: "max-age=31536000" }, customMetadata: { uploadedBy: "user-123", originalName: "document.txt" } }) // From FormData app.post("/upload", async (c) => { const formData = await c.req.formData() const file = formData.get("file") as File if (!file) { return c.json({ error: "No file" }, 400) } const key = `uploads/${crypto.randomUUID()}-${file.name}` await c.env.MY_BUCKET.put(key, await file.arrayBuffer(), { httpMetadata: { contentType: file.type } }) return c.json({ success: true, key }) })
// Get object const object = await env.MY_BUCKET.get("path/to/file.txt") if (!object) { return new Response("Not found", { status: 404 }) } // Stream to response (efficient for large files) return new Response(object.body, { headers: { "Content-Type": object.httpMetadata.contentType, "ETag": object.etag, "Cache-Control": "max-age=3600" } }) // Access metadata console.log(object.key) // File key console.log(object.size) // Size in bytes console.log(object.uploaded) // Upload date console.log(object.customMetadata) // Custom metadata
// List with pagination const listed = await env.MY_BUCKET.list({ limit: 100, // Max 1000 prefix: "images/", // Filter by prefix cursor: cursorToken, // For pagination include: ["customMetadata"] // Include metadata }) for (const obj of listed.objects) { console.log(obj.key, obj.size, obj.uploaded) } // Next page if (listed.truncated) { const nextPage = await env.MY_BUCKET.list({ cursor: listed.cursor }) }
// Delete single await env.MY_BUCKET.delete("path/to/file.txt") // Delete multiple await env.MY_BUCKET.delete([ "file1.txt", "file2.txt", "images/photo.jpg" ])
// Get metadata without downloading body const object = await env.MY_BUCKET.head("file.txt") if (!object) { return new Response("Not found", { status: 404 }) } console.log(object.size) console.log(object.etag) // Note: object.body is undefined for head()
import { S3Client, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3" import { getSignedUrl } from "@aws-sdk/s3-request-presigner" const S3 = new S3Client({ region: "auto", endpoint: `https://${env.ACCOUNT_ID}.r2.cloudflarestorage.com`, credentials: { accessKeyId: env.R2_ACCESS_KEY_ID, secretAccessKey: env.R2_SECRET_ACCESS_KEY } }) // Download URL (valid 1 hour) const downloadUrl = await getSignedUrl( S3, new GetObjectCommand({ Bucket: "my-bucket", Key: "file.txt" }), { expiresIn: 3600 } ) // Upload URL const uploadUrl = await getSignedUrl( S3, new PutObjectCommand({ Bucket: "my-bucket", Key: "upload.txt", ContentType: "text/plain" }), { expiresIn: 3600 } ) // Client can PUT/GET to these URLs
// ✅ Stream large files (don't load into memory) const object = await env.MY_BUCKET.get("large-file.mp4") return new Response(object.body, { headers: { "Content-Type": "video/mp4" } }) // ✅ Use head() for existence checks (no body transfer) const exists = await env.MY_BUCKET.head("file.txt") !== null // ❌ Wasteful - downloads entire file const exists = await env.MY_BUCKET.get("file.txt") !== null // ✅ Set cache headers for static files await env.MY_BUCKET.put("logo.png", file, { httpMetadata: { contentType: "image/png", cacheControl: "public, max-age=31536000, immutable" } })
app.get("/files/:key", async (c) => { const key = c.req.param("key") const object = await c.env.MY_BUCKET.get(key) if (!object) { return c.json({ error: "Not found" }, 404) } return new Response(object.body, { headers: { "Content-Type": object.httpMetadata.contentType, "Content-Disposition": `attachment; filename="${object.customMetadata?.originalName}"`, "ETag": object.etag } }) })
app.get("/files", async (c) => { const cursor = c.req.query("cursor") const prefix = c.req.query("prefix") const listed = await c.env.MY_BUCKET.list({ limit: 100, prefix, cursor, include: ["customMetadata"] }) return c.json({ files: listed.objects.map(obj => ({ key: obj.key, size: obj.size, uploaded: obj.uploaded, metadata: obj.customMetadata })), cursor: listed.truncated ? listed.cursor : null }) })
# Create bucket wrangler r2 bucket create my-bucket # Upload file wrangler r2 object put my-bucket/file.txt --file=./local.txt # List objects wrangler r2 object list my-bucket # Delete wrangler r2 object delete my-bucket/file.txt