How To Integrate Cloudflare R2 Storage with Laravel

Harry 5 min read
How To Integrate Cloudflare R2 Storage with Laravel
Table of Contents

Cloudflare R2 is a zero egress fee object storage which is compatible with the S3 API. This means you aren't at risk of vendor lock-in and can swap to another provider at any time.

Cloudflare R2 | Zero Egress Fee Distributed Object Storage | Cloudflare
Cloudflare R2 is an S3-compatible, zero egress-fee, globally distributed object storage. Move data freely and build the multi-cloud architecture you desire.

But why should you use Cloudflare R2?

There are a few solutions out there from Amazon S3 to Digital Ocean's Spaces each with their own trade-offs. Cloudflare R2 is one of the newer S3 alternatives on the block, offering zero egress fees and a generous 10GB of storage for free.

It's a great solution for getting started and even more so if you're already managing your domains with Cloudflare.

While R2 aims to be compatible with S3, not everything is supported. To see what's supported, check out the R2 documentation for a full list.

S3 API compatibility · Cloudflare R2 docs
R2 implements the S3 API to allow users and their applications to migrate with ease. When comparing to AWS S3, Cloudflare has removed some API …

Let's explore how we can use Cloudflare R2 with Laravel.

Setting Up Our Laravel Project

I'm going to assume you have a Laravel project ready to go. If not, go ahead and get one set up.

Then once you're ready, let's install the S3 Flysystem Adapter into our project:

$ composer require league/flysystem-aws-s3-v3:^3.0

If you are wondering why we're installing an S3 package. Remember, Cloudflare R2 is compatible with the S3 API.

Creating a Cloudflare R2 Bucket

What you need to do next is create a Cloudflare R2 bucket so that we have somewhere to store our files.

Open up your Cloudflare account and navigate to the R2 overview page. Here you'll see a button for creating a new bucket, go ahead and click that.

Cloudflare: creating a R2 bucket

Next, fill in the name of your bucket. The location can be left as auto unless you want to restrict it to be inside the EU.

Generating R2 Credentials

Now we have a bucket created, we'll need to generate some credentials so we can begin storing files from our Laravel application.

Head back to the R2 Overview page and find the link to "Manage R2 API Tokens" on the right side of the page.

Cloudflare: Manage R2 API Tokens

This will take you to a page of all your tokens with an additional button to "Create API Token".

Give your token a name so that you can recall what the token is for. And as for the permission make sure to only apply the permissions you need. If all you're doing is uploading and fetching objects then Object Read & Write is enough.

Cloudflare R2: Create API Token

It's also a good security practice to use one token per bucket. So be sure to lock the token to the bucket you created earlier. This limits the damage to the specific buckets should somebody manage to hijack your token.

TTL determines how long your token will last until it expires. You can make the token expire after 24 hours or several months, but unless you want to rotate keys out regularly then Forever is fine.

Finally, the Client IP Address Filtering lets you restrict the token to specific IP addresses. If you're security conscious and your servers have static IP addresses, then feel free to set this. But for testing it's fine to leave blank.

Cloudflare R2: Specifying a bucket

After creating your token you will be taken to a page with several keys. The keys we're interested in are the Access Key and Secret Access Key.

Configuring Laravel For Cloudflare R2

Open up the .env file in your Laravel application and we're now ready to wire up the credentials.

Take the Access Key and Secret Access Key from the step above and copy them into the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY respectively.


Set the AWS_BUCKET to the name of your bucket and leave the AWS_DEFAULT_REGION as us-east-1. R2 does not use the region value and will figure this out automatically if blank or left as us-east-1.


Now there are two AWS values left to configure. The AWS_URL and AWS_ENDPOINT.

The AWS_ENDPOINT is in the following format:


You can find this in your bucket's setting page for reference, so you can copy that. Just be sure to chop off the end of the URL where it adds your bucket's name.

Cloudflare R2: S3 API Url

The value of the AWS_URL depends on how you set up public access. You can either use a public R2 subdomain provided by Cloudflare or use your own domain.

Using the R2 subdomain is suitable for testing but be aware that this is rate-limited and does not utilising caching. For production, you will want to use your own domain.

For the sake of testing I'll use the Bucket URL. If you replicate this step, make sure to allow access.

Cloudflare R2: public access

Then take the public URL and paste it into the AWS_URL value in your .env:


Uploading Files to Cloudflare R2 With Laravel

Once everything is configured, all you need to do is upload a file as you would normally but specify S3 as the disk.

use Illuminate\Support\Facades\Storage;




The above will drop the file into a folder called uploads in your Cloudflare R2 bucket.

Should you want to read more about handling file uploads in Laravel, check out below:

Uploading Files with Laravel
If you’re looking to handle file uploads with Laravel then look no further! I will cover what you need to do to start handling file uploads in Laravel.
More from Harrk Blog

Harrk Blog

Programming nonsense, tutorials, and random musings about games and technology.

Great! You’ve successfully signed up.

Welcome back! You've successfully signed in.

You've successfully subscribed to Harrk Blog.

Success! Check your email for magic link to sign-in.

Success! Your billing info has been updated.

Your billing was not updated.