Image uploads are a common requirement for many web applications, and with the release of Next.js 13, it's easier than ever to perform secure image uploads to Cloudinary. In this tutorial, we'll walk through the steps to set up a basic Cloudinary image upload in a Next.js 13 project.
Before we get started, you'll need to create environment variables to store your Cloudinary credentials securely. Create a .env
file in your project directory and add the following variables:
NEXT_PUBLIC_CLOUDINARY_CLOUDNAME=
NEXT_PUBLIC_CLOUDINARY_API_KEY=
NEXT_PUBLIC_CLOUDINARY_UPLOAD_URL=https://api.cloudinary.com/v1_1/<YOUR_CLOUD_NAME>/image/upload
# Secret
CLOUDINARY_API_SECRET=
Remember to replace <YOUR_CLOUD_NAME>
with your actual Cloudinary cloud name.
Let's begin by creating an action file in our project. Create a new folder in /src
called actions
, and within that folder, create a file named upload.action.ts
.
// src/actions/upload.action.ts
"use server";
import { v2 as cloudinary } from "cloudinary";
cloudinary.config({
cloud_name: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUDNAME,
api_key: process.env.NEXT_PUBLIC_CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
secure: true,
});
Install the cloudinary
package using npm: npm install cloudinary
.
Now, let's create a function that will generate a signature and timestamp and return it.
// src/actions/upload.action.ts
export const getSignature = async () => {
const timestamp = Math.round(new Date().getTime() / 1000);
if (process.env.CLOUDINARY_API_SECRET) {
const signature = cloudinary.utils.api_sign_request(
{ timestamp, folder: "next" },
process.env.CLOUDINARY_API_SECRET
);
return { timestamp, signature };
} else {
throw new Error("CLOUDINARY_API_SECRET is not defined");
}
};
Now, let's implement the frontend part of the image upload.
// app/page.tsx
"use client";
import React from "react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { getSignature } from "@/actions/upload.action";
Set up the form with a file input:
// pages/upload.tsx
const page = () => {
return (
<form action={handleUpload} className="mt-3 w-4/6 mx-auto flex gap-2"><Input type="file" name="file" accept="image/*" /><Button>Upload</Button></form>
);
};
export default page;
Define the handleUpload
function to handle the file upload:
// app/page.tsx
const handleUpload = async (formData: FormData) => {
const files = formData.getAll("file");
if (files[0].name !== "") {
const { signature, timestamp } = await getSignature();
if (process.env.NEXT_PUBLIC_CLOUDINARY_API_KEY) {
formData.append("api_key", process.env.NEXT_PUBLIC_CLOUDINARY_API_KEY);
formData.append("signature", signature);
formData.append("timestamp", timestamp.toString());
formData.append("folder", "next");
} else {
throw new Error("Couldn't find Cloudinary API key");
}
const endpoint = process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_URL;
if (endpoint) {
const data = await fetch(endpoint, {
method: "POST",
body: formData,
}).then((res) => res.json());
console.log(data);
} else {
throw new Error("Endpoint not defined.");
}
} else {
throw new Error("No files were uploaded.");
}
};
In this function, we check if a file was selected, generate a signature and timestamp, append necessary data to the form, and send the payload to the Cloudinary API.
That's it! You've successfully set up a basic Cloudinary image upload in Next.js 13. You can now expand upon this foundation to build more advanced image upload features in your Next.js applications.