Skip to content

Join the Seedly owners community →

File Storage

Securing and Setting Up R2

Public and private files, setting up a bucket, and R2 pricing

Written by 3 min read2 activities
Sprout, your presenter

Sprout presents

Public files, private files, one bucket and a pricing table. I find bucket permissions genuinely thrilling, so let's set yours up properly.Public files, private files, one bucket and a pricing table. I find bucket permissions genuinely thrilling, so let's set yours up properly.

Sprout gestures between an open market stall of photos and a locked wooden safe
Some files are public, others must stay private

Security Considerations#

Not every file should be public. Think about what you're storing.

Public Files#

  • Profile pictures
  • Blog post images
  • Product photos

These can have public URLs that anyone can open.

Private Files#

  • Personal documents
  • Paid content
  • Sensitive uploads

These should require someone to be signed in. R2 supports "signed URLs," which are temporary links that expire after a set time. In this snippet, client is the S3 client you'll create in the next lesson, and the GetObjectCommand says which file to share.

import { GetObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
 
// Generate a temporary URL that expires in 1 hour
const command = new GetObjectCommand({ Bucket: 'my-bucket', Key: 'invoices/1234.pdf' })
const signedUrl = await getSignedUrl(client, command, { expiresIn: 3600 })

getSignedUrl lives in its own package, so install it with npm install @aws-sdk/s3-request-presigner next to @aws-sdk/client-s3.

Only signed-in users can request a signed URL, and it only works for a limited time. Somebody forwards the link next week? Dead link.

Setting Up R2#

Here's the basic process to get R2 up and running.

Step 1. Create Cloudflare Account#

Sign up at cloudflare.com. R2 comes with free monthly usage (more on that in Pricing below).

Step 2. Enable R2#

In the Cloudflare dashboard, go to Storage & databases, then R2, and go through the checkout to add an R2 subscription. Yep, even the free usage needs that step, so don't be surprised if it asks for billing info. You don't pay anything until you go past the free amounts.

Step 3. Create a Bucket#

A bucket is where your files live. Give it a name that actually describes what's in it (future you will thank you).

Step 4. Get API Credentials#

On the R2 page, find API Tokens under Account Details and click Manage. Create a token with only the permissions your app needs, and you'll get an Access Key ID and a Secret Access Key. Copy the secret RIGHT AWAY, because Cloudflare only shows it once.

Step 5. Connect Your App#

Use the S3 SDK in your code to upload and grab files.

Pricing#

Sprout hands over a paper ticket with a small hourglass attached in front of a locked safe
Signed URLs are temporary passes that expire

R2 pricing is simple and pretty cheap. Here's the standard storage pricing as of October 2026 (always double check the R2 pricing page before you promise a client anything).

  • Free every month. 10 GB of storage, 1 million Class A operations (writes, like uploads) and 10 million Class B operations (reads)
  • Storage after that. $0.015 per GB per month
  • Operations after that. $4.50 per million Class A and $0.36 per million Class B
  • Egress. FREE! (This is where the big savings are)

For context, a small app storing 10 GB of images fits inside the free tier, so it costs $0. Even at 100 GB you'd pay for the 90 GB over the free amount, which works out to about $1.35 a month. That's thousands and thousands of images for less than a fancy coffee.

This lesson ends with 2 short activities.