Begin by accessing your Cloudflare dashboard to create a new R2 bucket. This storage bucket will serve as the destination for all your file uploads from the Next.js application.
After creating the bucket, note down the necessary credentials, including the Access Key ID and Secret Access Key. These credentials are essential for authenticating API requests from your Next.js application to Cloudflare R2.
To enable your Next.js application to communicate with the R2 bucket, configure the Cross-Origin Resource Sharing (CORS) policy. This setting ensures that your application can perform necessary HTTP requests to the bucket without facing origin-related restrictions.
Utilize the AWS SDK for JavaScript to interact with Cloudflare R2. Install the @aws-sdk/client-s3
package, which is compatible with R2 due to its support for the S3 API.
npm install @aws-sdk/client-s3
Additionally, install formidable
for parsing incoming form data, which is essential for handling file uploads.
npm install formidable
Create a .env.local
file at the root of your Next.js project to securely store your Cloudflare R2 credentials and configuration details. This file should include the following variables:
R2_ACCESS_KEY_ID=your_access_key_id
R2_SECRET_ACCESS_KEY=your_secret_access_key
R2_ACCOUNT_ID=your_account_id
R2_BUCKET_NAME=your_bucket_name
R2_ENDPOINT=https://your-account-id.r2.cloudflarestorage.com
Ensure that this file is excluded from version control to maintain the security of your credentials.
Create an API route (e.g., pages/api/upload.js
for JavaScript or app/api/upload/route.ts
for TypeScript) to handle the file upload process. This handler will utilize the AWS SDK to upload files to your R2 bucket.
// pages/api/upload.js
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import formidable from "formidable";
import fs from "fs";
export const config = {
api: {
bodyParser: false,
},
};
const s3Client = new S3Client({
region: "auto",
endpoint: process.env.R2_ENDPOINT,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
},
});
const uploadFileToR2 = async (file, bucketName, key) => {
const fileContent = fs.readFileSync(file.filepath);
const params = {
Bucket: bucketName,
Key: key,
Body: fileContent,
ContentType: file.mimetype,
};
await s3Client.send(new PutObjectCommand(params));
};
export default async function handler(req, res) {
if (req.method === "POST") {
const form = formidable({ multiples: false });
form.parse(req, async (err, fields, files) => {
if (err) {
res.status(500).json({ error: "Failed to parse form data" });
return;
}
try {
const file = files.file;
const bucketName = process.env.R2_BUCKET_NAME;
const key = `${Date.now()}_${file.originalFilename}`;
await uploadFileToR2(file, bucketName, key);
res.status(200).json({ message: "File uploaded successfully", key });
} catch (error) {
console.error(error);
res.status(500).json({ error: "File upload failed" });
}
});
} else {
res.status(405).json({ error: "Method not allowed" });
}
}
The API route disables the default body parser to handle multipart form data using formidable
. Upon receiving a POST request, it parses the form data, reads the file from the temporary location, and uploads it to Cloudflare R2 using the configured S3 client.
Develop a frontend component that allows users to select and upload files. This component will interact with the API route to send the selected files for storage.
// components/UploadComponent.js
'use client';
import { useState } from "react";
export default function UploadComponent() {
const [file, setFile] = useState(null);
const [message, setMessage] = useState("");
const handleSubmit = async (e) => {
e.preventDefault();
if (!file) {
setMessage("Please select a file first!");
return;
}
const formData = new FormData();
formData.append("file", file);
try {
const res = await fetch("/api/upload", {
method: "POST",
body: formData,
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
setMessage(`File uploaded successfully: ${data.key}`);
} catch (error) {
console.error("Upload error:", error);
setMessage("Upload failed");
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="file"
name="file"
required
/>
<button
type="submit"
disabled={!file}
>
Upload
</button>
{message && <p>{message}</p>}
</form>
);
}
Incorporate the UploadComponent
into your Next.js pages where you want to provide file upload functionality. For example, you can include it in the pages/index.js
:
// pages/index.js
import UploadComponent from "../components/UploadComponent";
export default function Home() {
return (
<div>
<h1>Upload File to Cloudflare R2</h1>
<UploadComponent />
</div>
);
}
Start your Next.js development server using the command:
npm run dev
Navigate to the page containing the UploadComponent
. Select a file using the input field and submit the form. Upon successful upload, a confirmation message with the file key will appear.
Access your Cloudflare R2 dashboard and verify that the uploaded file appears in the specified bucket. Ensure that the file's metadata, such as the name and content type, match the uploaded data.
Ensure that your environment variables are securely stored and not exposed publicly. Use environment-specific configurations to manage different stages of your application (development, staging, production).
Implement asynchronous file processing and consider using CDN integrations to enhance the performance of file deliveries. Utilize caching strategies to reduce latency and improve user experience.
Incorporate comprehensive error handling mechanisms both on the client and server sides. This includes handling network issues, validating file types and sizes, and providing meaningful feedback to users.
Implement strategies for managing the lifecycle of uploaded files, such as setting expiration dates, organizing files into logical directories, and implementing file versioning if necessary.
Fine-tune your CORS settings in the Cloudflare R2 dashboard to restrict access to trusted domains only. This minimizes security risks associated with cross-origin requests.
Integrating Cloudflare R2 with Next.js facilitates efficient and scalable file storage solutions for modern web applications. By following the outlined steps—setting up Cloudflare R2, configuring your Next.js environment, implementing API routes for uploads, and creating user-friendly frontend components—you can establish a robust file upload system. Emphasizing security, performance, and error handling further ensures that your application remains reliable and secure as it scales.