HeftySend

Back to Blog
HeftySend TeamSeptember 11, 2025
General

Build a Cloudflare R2 Uploader From Scratch

A practical guide to building your own Cloudflare R2 uploader. Get hands-on with code, or discover a simpler, no-code alternative for secure file uploads.

cloudflare r2 uploader
cloudflare r2
node js file upload
object storage

Look, getting files into the cloud can be a real pain. We've all been there. You hear about cool tech like Cloudflare R2 and its game-changing zero egress fees, but then you hit a wall just trying to figure out how to get your files in there. This is where a custom Cloudflare R2 uploader comes in—it puts you back in the driver's seat.

Why Bother Building a Custom Cloudflare R2 Uploader?

So, why go through the effort of building your own uploader when other tools exist? For me, it boiled down to two simple things: control and cost.

When you're dealing with a web app that handles large media files, user-generated content, or even just a reliable backup system, the off-the-shelf options can feel clunky and restrictive. Building your own lets you shape the entire process to fit exactly what you need. You’re not just moving files around; you’re crafting a workflow that slots perfectly into your application.

Gaining Full Control Over Your Data

When you build it yourself, you call all the shots. Every single part of the process is yours to define.

  • The User Experience: You can design an interface that actually matches your brand and doesn't feel like a clunky, third-party add-on.
  • Rock-Solid Security: Implement your own security protocols, like presigned URLs, to make sure your secret keys are never, ever exposed on the client's side.
  • Seamless Workflow Integration: This is the big one. Your uploader can plug directly into your backend logic, automatically triggering database updates or other actions the moment an upload is complete.

The real magic of a custom uploader is that it stops being a simple "file mover" and becomes a core piece of your application's architecture. That's a level of deep integration you just can't get from a generic tool.

The R2 Advantage: No More Surprise Bills

Let’s be honest, the best part about Cloudflare R2 is the pricing. It completely gets rid of the expensive egress fees that blindside developers using other major cloud storage providers. It’s an incredibly cost-effective and scalable object storage solution, built for everything from delivering web content to housing massive data lakes.

This pricing model makes R2 a smart, strategic choice for anyone trying to balance high performance with a predictable budget.

Of course, not everyone has the time or desire to code an uploader from the ground up. If your main goal is just a secure, dead-simple way to get files into your R2 bucket without the engineering headache, our app HeftySend provides a ready-made solution. It gives you a simple, shareable upload portal that connects right to your storage, letting you skip the code and get the same end result.

Setting Up Your Cloudflare R2 Environment

Before we can even think about writing code for our uploader, we need to lay the groundwork in the Cloudflare dashboard. Think of it as setting up the foundation before you build the house—get this part right, and everything else becomes much smoother. Honestly, this is where most people stumble, getting tangled up in credentials and permissions.

First up, you need a place for your files to live. In the R2 world, this is called a bucket. It's simply a unique container for all your data. If you're new to this, it's worth understanding how R2 fits into the broader world of storage. You can get a great primer on various storage system types like object storage to really understand the tech we're using here.

Creating Your First R2 Bucket

Let's dive in. Head over to your Cloudflare dashboard, find R2 in the sidebar, and click "Create bucket." You'll need to give it a name that's unique across all of Cloudflare—something descriptive like my-awesome-app-uploads usually does the trick.

Image

The screenshot above shows you just how simple the interface is. Once it’s created, take note of your Account ID and the bucket's details. You'll need these soon.

With our bucket ready to go, the next step is to create a secure way for our application to actually talk to it. That's where API tokens come in.

Before we start generating keys, let's quickly review the essential pieces you'll be grabbing from your Cloudflare account.

Key Cloudflare R2 Setup Components

Component Purpose Where to Find It
Bucket Name The unique identifier for your storage container. Cloudflare Dashboard → R2
Account ID A unique ID for your entire Cloudflare account. Cloudflare Dashboard → R2 Overview (right sidebar)
Access Key ID The "username" for your API token. R2 → Manage R2 API Tokens (after creating a token)
Secret Access Key The "password" for your API token. R2 → Manage R2 API Tokens (shown only once on creation)

This table is your checklist. Make sure you have all these items handy as we move on to creating the actual credentials.

Generating Secure API Tokens

You wouldn't hand out the master key to your house, would you? The same logic applies here. We're going to create a special key—an API token—that only has permission to read and write files in our new bucket. This follows the principle of least privilege, and it's an absolute must for security.

In the R2 section of your dashboard, find "Manage R2 API Tokens" and click to create a new one.

Here’s exactly what to set:

  • Permissions: Select Object Read & Write. This is all our uploader needs. Don't be tempted to grant Admin Read & Write unless you have a very specific reason.
  • Bucket(s): Apply the token only to the specific bucket you just created. This walls it off from accessing any other buckets in your account.
  • Time to Live (TTL): You can set the token to expire, which is a fantastic practice for temporary or short-term access keys.

My Personal Tip: The moment you create your token, copy the Access Key ID and the Secret Access Key and store them somewhere safe, like a password manager. The Secret Access Key is only shown once. If you lose it, you have to start over and generate a new token. No exceptions!

Of course, if this all feels a bit tedious, you're not alone. This is exactly why we created HeftySend. Our app handles the secure connection to your R2 bucket for you, turning this multi-step setup into a simple, two-minute task without you ever having to manually manage an API token. Give it a try!

Crafting the Uploader Backend with Node.js

Alright, with our Cloudflare R2 bucket prepped and ready, it's time for the fun part: building the engine that actually powers our uploader. We’ll be spinning up the backend logic using Node.js.

The best part? Cloudflare designed R2 to be compatible with the AWS S3 API. This is fantastic news for us, because it means we can use the battle-tested AWS S3 SDK to do all the heavy lifting. No need to learn a brand-new library.

Our main goal here is to create a secure endpoint that generates presigned URLs. This isn't just a fancy trick; it's the industry-standard way to handle browser-based uploads for a very good reason. It keeps your secret keys completely safe on the server, where they belong. Your front-end code never even touches them, which is a massive security win.

Setting Up a Basic Express Server

First things first, we need a simple server to handle requests. I'm a big fan of Express.js because it's lightweight and gets the job done without a ton of ceremony. If you're starting from a blank slate, a few quick commands will get you rolling.

You'll need to pull in Express and the AWS SDK packages:
npm install express @aws-sdk/client-s3 @aws-sdk/s3-request-presigner

Once those are installed, we can whip up a barebones server. This initial code just gets our server up and running, giving us a foundation to build the uploader logic on top of.

Here’s a quick visual of how the backend pieces fit together, from snagging your API keys to connecting with your R2 bucket.

As the diagram shows, keeping your credentials secure in environment variables is the critical bridge between your R2 API token and your application's code.

Generating Secure Presigned URLs

Now for the real magic. We need to create the core function that makes this whole thing work. We'll build an endpoint—let's call it /generate-upload-url—that our frontend can hit. This endpoint will use our R2 credentials to ask Cloudflare for a special, one-time-use URL that grants permission to upload a specific file.

To pull this off, we need to initialize the S3 client with our Cloudflare R2 details. Remember those API tokens and the Account ID we stashed away earlier? Now's the time to load them from your environment variables (.env file) to keep them out of your codebase. Never, ever hardcode your keys. You can find some great best practices for securing API keys in your projects if you need a refresher.

The function will take something like a filename and file type from the frontend's request. It then uses the @aws-sdk/s3-request-presigner library to generate the URL. We can even add an expiration time, like 60 seconds, so the link is only valid for a super short window.

This approach is so elegant because all the credential management and heavy lifting happens entirely on your server. Your frontend only ever sees a temporary, tokenized URL, which effectively sandboxes the entire upload process.

Of course, building and maintaining a backend like this takes time and effort. If your goal is just to get files into R2 without wrangling servers or code, a more direct solution might be a lifesaver. With our app, HeftySend, you connect directly to your R2 bucket, giving you a ready-made, secure upload portal without writing a single line of backend code.

The final piece of our endpoint is to handle any potential errors gracefully. If for some reason the SDK can't generate a URL, our server should send back a clear error message. This helps immensely when you're trying to debug things on the frontend later on.

With this backend in place, we now have a functional, secure system that's ready to start accepting files.

Building the Frontend Uploader Interface

Alright, our backend is ready to dish out secure upload links. Now, let's build the part the user actually sees and interacts with. This is where we’ll put together a simple but effective HTML and JavaScript frontend to complete our Cloudflare R2 uploader.

Image

We're going to keep this part straightforward. The main goal is a clean interface that lets someone pick a file from their device and get it into your R2 bucket without any fuss.

The whole thing works like a two-step dance. First, our frontend asks the backend for a special, one-time upload URL. Second, it uses that URL to send the file directly to your R2 bucket.

Designing the HTML Form

The HTML is the easy part. All we really need is a basic form with a file input and a button. This is the skeleton of our uploader.

Here’s a minimal example you can get started with:

R2 Uploader

Upload a File to Cloudflare R2

<script src="uploader.js"></script>

This simple structure gives us everything we need: an <input type="file"> for choosing a file, a <button> to kick things off, and a handy <p> tag where we can show the user what’s happening.

Handling the Upload with JavaScript

Now for the brains of the operation. We'll use JavaScript's fetch API, which is built right into modern browsers, to manage the entire upload process.

I'll break down the key steps our script needs to cover:

  1. Listen for the Form Submission: First, we need to grab the form and stop it from doing its default "submit" action. This lets us take control.
  2. Get the Selected File: When the user clicks "Upload," we'll get the file object from the input field.
  3. Request the Presigned URL: Next, we send a POST request over to our /generate-upload-url backend endpoint. We'll include the file's name and type, and in return, the backend will send back that secure, temporary URL.
  4. Upload the File to R2: Finally, we make a PUT request straight to the presigned URL we just got, with the file's data as the request body.

This two-step process is crucial for security and efficiency. The browser uploads directly to R2 using a temporary URL, so the user's data never has to pass through our server. This cuts down on server load and keeps the whole operation incredibly fast.

The entire flow is asynchronous, so we can give feedback to the user along the way. We'll update that "status" paragraph to let them know if the upload was a success or if something went wrong.

While building this yourself is a fantastic learning experience, I know firsthand that not everyone wants to mess with frontend code and backend servers. If you just need a polished, secure upload portal for your R2 bucket without writing any code, this is exactly the problem our app, HeftySend, was built to solve. You can connect your R2 bucket in a couple of clicks and get a shareable link instantly, saving you all this development time.

The Simpler Path: The HeftySend Advantage

Building your own custom Cloudflare R2 uploader is a fantastic learning experience, and now you've got a solid grasp on what it takes, from the backend code to the frontend interface.

But let's be honest for a second. That path means you're on the hook for managing a server, juggling credentials securely, and keeping the code maintained.

What if your real goal isn't to become a part--time sysadmin, but just to get files into R2 easily and securely? That's exactly why we built HeftySend. Think of it as a secure, polished portal that hooks directly into your R2 bucket, minus all the engineering headaches.

No Coding, Just Uploading

With HeftySend, you get a simple, shareable upload link you can hand off to clients, team members, or just use for yourself. There’s no coding and no server maintenance. You get the same end result as our custom build, but with a whole suite of powerful features ready to go from day one.

  • Password Protection: Lock down your upload pages with a password.
  • Link Expirations: Automatically disable links after a set time or a certain number of downloads.
  • A Clean UI: A professional, intuitive interface that your clients and team will actually enjoy using.

Here’s a look at the clean, drag-and-drop interface you get right out of the box. It’s built to make the whole process seamless.

Image

This kind of user-friendly design means anyone can start uploading large files to your R2 bucket immediately—no training required.

Get Started in Minutes, Not Days

Connecting your R2 bucket to HeftySend takes less than two minutes. Seriously. You just provide your credentials, and we handle the secure connection, instantly giving you a private upload portal. It's the perfect alternative if your main goal is moving files, not kicking off a new weekend coding project.

We created HeftySend for people who value their time. We took care of all the complex engineering so you can focus on your actual work, not on maintaining another piece of software.

Instead of spending hours or days building and debugging your own solution, you can have a more powerful and polished uploader running in the time it takes to grab a coffee. If that sounds like a good trade-off, you can explore the different options over at HeftySend's pricing plans. It’s the fast track to a professional-grade Cloudflare R2 uploader.

Common Questions About Cloudflare R2 Uploaders

https://www.youtube.com/embed/ZPw0jrwfAeA

When you first dive into building a custom Cloudflare R2 uploader, you’re bound to hit a few common roadblocks. I see the same questions pop up time and again, so let's walk through them. Getting these answers straight from the start will save you a ton of headaches.

One of the first things people get stuck on is permissions. Do you really need to give your uploader full admin access to your R2 account?

Absolutely not. You should always operate on the principle of least privilege. An Object Read & Write permission is all you need, and you should scope it to the specific bucket you're using. Anything more is an unnecessary security risk.

Troubleshooting and Common Sticking Points

Another big question I get is about presigned URLs. Why bother with them? Can't you just sling the file up from the browser with your API key?

Please, don't do that. Ever. Exposing your secret API keys on the client-side is a massive security hole just waiting to be exploited.

Presigned URLs are the industry-standard for a reason: they keep your secret keys safe on your backend. The browser only ever receives a temporary, single-use token to upload one specific file. It's just a much smarter, more secure way to handle uploads.

If your uploads are failing, it’s almost always one of three things. Here’s my personal checklist:

  • CORS Configuration: Is your bucket's Cross-Origin Resource Sharing (CORS) policy set up correctly in the Cloudflare dashboard? A bad or missing policy is the #1 reason browser-based uploads fail.
  • Token Expiration: If you’re using short-lived presigned URLs (and you should be), make sure the upload actually starts before the URL dies. A one-minute expiration is great for security, but it can be a little tight if your user is on a slow connection.
  • Endpoint Mismatch: This one is sneaky. Double-check, then triple-check that your S3 client is pointing to the right Cloudflare R2 endpoint URL. It needs to include your unique Account ID, and it's a tiny detail that’s incredibly easy to get wrong.

When to Build vs. When to Buy

This brings us to the big-picture question: "Do I really need to go through all this for my project?"

Building your own uploader is a fantastic learning experience, no doubt. But it's not always the most practical path. If your main goal is just to get files into R2 reliably and securely—without the ongoing headache of maintaining custom code—then building from scratch might be total overkill.

That’s exactly where a ready-made solution becomes a lifesaver, and it's why we created our app, HeftySend.


If you want to skip the code entirely and get a powerful, secure R2 upload portal running in minutes, HeftySend is the perfect answer. You get all the benefits of R2 storage paired with a polished, user-friendly interface. Sign up and connect your R2 bucket today at HeftySend.com.

HeftySend

Send hefty files fast - simple, fast, and secure.

Features

  • File Sharing
  • Custom Pages
  • Expiration Settings

Company

  • About Us
  • Blog
  • Tutorials
  • Contact

Legal

  • Terms of Service
  • Privacy Policy

© 2025 HeftySend. Based in the Isle of Man.

Built with ❤️ for simple file sharing