
npm i next-cloudinary

복사 후 .env 파일에

다음과 같이 작성해준다. cloud name은 cloudinary 가입 이후 dashboard에 가면 내 클라우드 네임을 알 수 있다.
"use client";
import { useState, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { ImagePlus, Trash } from "lucide-react";
import Image from "next/image";
import { CldUploadWidget } from "next-cloudinary";
interface ImageUploadProps {
disabled: boolean;
onChange: (value: string) => void;
onRemove: (value: string) => void;
value: string[];
}
const ImageUpload = ({
disabled,
onChange,
onRemove,
value,
}: ImageUploadProps) => {
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
const onSuccess = (result: any) => {
onChange(result.info.secure_url);
};
if (!isMounted) {
return null;
}
return (
<div>
<div className="mb-4 flex items-center gap-4">
{value.map((url) => (
<div
key={url}
className="relative w-[200px] h-[200px] rounded-md overflow-hidden"
>
<div className="z-10 absolute top-2 right-2">
<Button
type="button"
variant="destructive"
size="icon"
onClick={() => onRemove(url)}
>
<Trash className="h-4 w-4" />
</Button>
</div>
<Image fill className="object-cover" alt="Image" src={url} />
</div>
))}
</div>
<CldUploadWidget onSuccess={onSuccess} uploadPreset="<your preset>">
{({ open }) => {
const onClick = () => open();
return (
<Button
type="button"
disabled={disabled}
variant="secondary"
onClick={onClick}
>
<ImagePlus className="mr-2 h-4 w-4" />
Upload an Image
</Button>
);
}}
</CldUploadWidget>
</div>
);
};
export default ImageUpload;
이미지 업로드 컴포넌트를 생성해준다.

onUpload는 더 이상 권장되지 않으므로 onSuccess를 사용해준다.
your preset 자리에는
cloudinary settings에서


Upload의 Add upload preset으로 생성이 가능하다. 저기 프리셋 이름을 복사해 붙여넣기 해준다.
Mode는 unSigned를 선택해준다.
Signed 업로드
보안이 더 높고, 서버가 필요하며, 동적 설정이 가능하고, 업로드 시 직접 설정하며, API 키와 시크릿을 서버에서 관리하고, 높은 보안이 필요한 경우에 사용되며, 서버를 거쳐 약간 느릴 수 있고, 구현이 더 복잡하며, 실시간 제어가 가능하고, 확장성이 높다.
Unsigned 업로드
보안이 상대적으로 낮고, 서버가 불필요하며, preset에 제한되고, 미리 정의된 preset을 사용하며, API 키만 클라이언트에 노출되고, 빠른 구현이 필요한 경우에 사용되며, 직접 업로드로 상대적으로 빠르고, 구현이 더 간단하며, 실시간 제어가 제한적이고, preset 수정이 필요할 수 있다.