Upload Images to Cloudinary in Next.js (Using App Router)
react
web-development
cloudinary
typescript
nextjs
In this blog, we’ll walk through the steps to upload images to Cloudinary in a Next.js application. We’ll use the App Router (introduced in Next.js 13) and Server Actions to handle the image upload process. By the end of this guide, you’ll have a simple and functional image upload feature in your Next.js app.
What is Cloudinary?
Cloudinary is a cloud-based service that helps developers manage, optimize, and deliver images and videos. It provides an easy-to-use API for uploading, transforming, and serving media files.
Prerequisites
Before we start, make sure you have the following:
A Cloudinary account (you can sign up for free at cloudinary.com).
A Next.js project set up with the App Router (Next.js 13 or later)
Step 1: Set Up Cloudinary
Create a Cloudinary Account: If you don’t have one, sign up at cloudinary.com.
Get Your Cloudinary Credentials: After signing up, go to your Cloudinary dashboard and note down your:
Cloud Name
API Key
API Secret
These credentials will be used to upload images to your Cloudinary account.
Cloudinary Dashboard
Step 2: Install Required Packages
To interact with Cloudinary, we’ll use the cloudinary package. Install it using npm or yarn:
npm install cloudinary
Step 3: Set Up Environment Variables
Store your Cloudinary credentials securely in a .env.local file:
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
Step 4: Create a Server Action for Image Upload
In Next.js, Server Actions allow you to run server-side code directly from your components. We’ll create a Server Action to handle the image upload process.
Create a new file called actions.ts in your project:
// app/action.ts
"use server";
import { v2 as cloudinary, UploadApiResponse } from "cloudinary";
// Configure Cloudinary
cloudinary.config({
cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});
// Server Action to upload image
export async function uploadImage(formData: FormData) {
const file = formData.get("file") as File;
if (!file) {
throw new Error("No file uploaded");
}
// Convert file to buffer
const arrayBuffer = await file.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
// Upload to Cloudinary
const result: UploadApiResponse | undefined = await new Promise(
(resolve, reject) => {
cloudinary.uploader
.upload_stream(
{
resource_type: "auto", // Automatically detect image/video
folder: "nextjs-uploads", // Optional: Organize files in a folder
},
(error, result) => {
if (error) reject(error);
else resolve(result);
}
)
.end(buffer);
}
);
return result;
}
Step 5: Create the Upload Form
Now, let’s create a form in a Next.js client component to upload images. In this component we’ll use the Server Action we just created.
lets Create a new file called UploadForm.tsx:
// app/components/UploadForm.tsx
"use client";
import { uploadImage } from "@/app/actions";
import { useState } from "react";
export default function UploadForm() {
const [imageUrl, setImageUrl] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setLoading(true);
const formData = new FormData(e.currentTarget);
const result = await uploadImage(formData);
console.log(result);
if (result) {
setImageUrl(result?.secure_url);
}
setLoading(false);
};
return (
<div className="bg-white p-4 rounded-lg shadow w-80">
<form onSubmit={handleSubmit}>
<input
type="file"
name="file"
accept="image/*"
className="w-full border p-2 rounded mb-4"
required
/>
<button
type="submit"
disabled={loading}
className="w-full bg-blue-600 text-white py-2 rounded disabled:bg-gray-400"
>
{loading ? "Uploading..." : "Upload Image"}
</button>
</form>
{imageUrl && (
<div className="mt-4 text-center">
<p className="text-green-600">Image uploaded successfully!</p>
<img src={imageUrl} alt="Uploaded" className="mt-2 w-full rounded" />
</div>
)}
</div>
);
}
Step 6: Use the Upload Form in a Page
Finally, let’s use the UploadForm component in our page.
// app/page.tsx
import UploadForm from "@/components/UploadForm";
export default function Home() {
return (
<main className="min-h-screen flex items-center justify-center gap-8 flex-col bg-gray-100 ">
<h1 className="text-2xl font-bold">Upload Image to Cloudinary</h1>
<UploadForm />
</main>
);
}
Step 7: Test the Application
Run npm run dev and test the upload feature. If everything is set up correctly, the image will be uploaded to Cloudinary, and you’ll see a preview of the uploaded image. Here’s what the final result looks like:
Conclusion
That’s it! You’ve successfully built a feature to upload images to Cloudinary in a Next.js app using the App Router and Server Actions. This setup is simple, efficient, and scalable for most use cases.
Read More