How to Integrate Cloudflare R2 with Next.js 15 and Deploy on Vercel from GitHub (2025 Guide)

September 12, 2025
3 min read
How to Integrate Cloudflare R2 with Next.js 15 and Deploy on Vercel from GitHub (2025 Guide)

Quick TL;DR

  • Create R2 bucket + access keys in Cloudflare.
  • Add keys to Vercel environment variables.
  • Make a server API route in Next.js that creates a presigned PUT URL (using AWS S3 SDK).
  • Upload from the browser with the presigned URL.
  • Push to GitHub → connect to Vercel → deploy.
Short, no fluff — you’ll be done in minutes.

Why R2 is better than S3 (beginner-friendly)

  • Cheaper/no egress to Cloudflare CDN — R2 avoids heavy egress costs when paired with Cloudflare’s edge.
  • S3-compatible API — you can use the same AWS SDK code with a custom endpoint.
  • Simple pricing for static object storage — ideal for uploads & static assets.
  • Global edge delivery with Cloudflare built-in.

Downside: S3 still has deeper enterprise features. But for cost + performance, R2 wins for most web apps.

Step-by-step guide

1) Create R2 bucket + Access Keys

  1. Go to Cloudflare Dashboard → Workers & R2Create bucket.
  2. Find your Account ID (needed for endpoint).
  3. Create Access Key (Access Key ID + Secret). Save both.

2) Add environment variables in Vercel

R2_ACCOUNT_ID=your_account_id
R2_BUCKET=your_bucket_name
R2_ACCESS_KEY_ID=your_access_key
R2_SECRET_ACCESS_KEY=your_secret
R2_REGION=auto
  

3) Install AWS SDK in your Next.js app

npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
  

4) Create a server API route for presigned URL

// app/api/upload-url/route.ts
import { NextResponse } from "next/server";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const s3 = new S3Client({ region: process.env.R2_REGION || “auto”, endpoint: https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com, credentials: { accessKeyId: process.env.R2_ACCESS_KEY_ID || “”, secretAccessKey: process.env.R2_SECRET_ACCESS_KEY || “”, }, });

export async function POST(req: Request) { try { const { name, type } = await req.json(); const key = uploads/${Date.now()}-${Math.random().toString(36).slice(2,8)}-${name};

const cmd = new PutObjectCommand({
  Bucket: process.env.R2_BUCKET,
  Key: key,
  ContentType: type,
});

const url = await getSignedUrl(s3, cmd, { expiresIn: 60 });

return NextResponse.json({ url, key });

} catch (e: any) { return NextResponse.json({ error: e.message }, { status: 500 }); } }

5) Upload from client

async function uploadFile(file) {
  const res = await fetch("/api/upload-url", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ name: file.name, type: file.type })
  });
  const { url, key } = await res.json();

await fetch(url, { method: “PUT”, headers: { “Content-Type”: file.type }, body: file });

return { key, url }; }

6) Deploy on Vercel

  1. Push code to GitHub.
  2. Import repo into Vercel.
  3. Add same env vars in Vercel settings.
  4. Deploy — done!

Final Checklist

  • [ ] R2 bucket + Access Key created
  • [ ] Env vars in Vercel
  • [ ] Presigned URL route added
  • [ ] Client upload function works
  • [ ] GitHub → Vercel connected

End note: I personally run my site on R2 — it saves cost, gives me Cloudflare’s CDN edge, and still lets me use familiar S3 code. For most devs, it’s the best combo of speed + budget.

Recent Articles

Deploy Your Hugo + Tailwind v4 Website to Cloudflare Pages Automatically with GitHub Actions

November 1, 2025

This guide shows how to automatically deploy a Hugo + Tailwind CSS site to Cloudflare Pages every time you push code to your GitHub repository. It’s written for beginners — no advanced DevOps …

How I Optimized Core Web Vitals to 100% on My HugoGo Website

October 31, 2025

Optimizing a HugoGo website to achieve a perfect 100% Core Web Vitals score is completely possible without major code rewrites. Hugo’s static site generation already gives a strong base — with server …

Best Nodejs Package Hicons for HugoGo: Effortless SVG Icon Management

October 31, 2025

SVG icons are a staple of modern web design, but managing them in static site generators like Hugo can be tedious. If you’ve ever found yourself manually copying SVG code, worrying about layout bloat, …

Why Your First Website Should Be Built with HugoGo Instead of WordPress

October 30, 2025

When it comes to building your first website, most people immediately think of WordPress. It’s popular, widely supported, and has tons of plugins but is it really the best choice for every …

Why Hugo static website generation Can Be Better Than Next.js in 2026

October 30, 2025

When it comes to building fast, secure, and scalable websites, Hugo and Next.js both stand tall. But depending on your goals — especially if you’re running a blog, portfolio, agency site, or a …

Web Development on Android Using UserLAnd and CX File Explorer (Node.js)

October 15, 2025

If you don't have a laptop or a PC, learning web development or starting freelancing is no longer impossible! UserLAnd is an excellent solution for creating a complete development environment using an …