{"id":35759,"date":"2024-09-26T07:00:00","date_gmt":"2024-09-26T14:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=35759"},"modified":"2025-10-22T13:44:58","modified_gmt":"2025-10-22T20:44:58","slug":"next-js-cloudinary-upload-transform-moderate-images","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images","title":{"rendered":"Using Next.js and Cloudinary to Upload, Transform, and Moderate Your Images"},"content":{"rendered":"\n<p>In this blog post, we&#8217;ll show you how to upload images with a single button, store them in specific folders, enable manual moderation, and display these images in your app filtered by tags \u2013 all by using <a href=\"http:\/\/next.js\">Next.js<\/a>.<\/p>\n\n\n\n<p>First, we\u2019ll need to set up the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>A free Cloudinary account<\/strong>. If you haven&#8217;t already, <a href=\"https:\/\/cloudinary.com\/users\/register_free\">sign up for a Cloudinary account<\/a>. It&#8217;s where our images will live and be managed.<\/li>\n\n\n\n<li><strong>Next.js App Router<\/strong>. Make sure you have the <a href=\"http:\/\/next.js\">Next.js App Router<\/a>. We can use the pages router, but for this demo, let&#8217;s stick with the App Router to stay on the cutting edge.<\/li>\n\n\n\n<li><strong>Next-Cloudinary package<\/strong>. The <a href=\"https:\/\/next.cloudinary.dev\/installation\">next-cloudinary package<\/a> is a handy tool that makes integrating Cloudinary into our Next.js app a breeze.<\/li>\n\n\n\n<li><strong>Cloudinary package<\/strong>. This is the <a href=\"http:\/\/node.js\">Cloudinary SDK for Node.js<\/a>.<\/li>\n\n\n\n<li><strong>Some cool images!<\/strong> This tutorial will demonstrate how to upload images. So go ahead and prepare some awesome, good-looking images for our tests.<\/li>\n<\/ul>\n\n\n\n<p>Once we have our Cloudinary account and images ready, it&#8217;s time to kick things off by setting up our Next.js app. Let&#8217;s start with this command:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npx<\/span> <span class=\"hljs-selector-tag\">create-next-app<\/span><span class=\"hljs-keyword\">@latest<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>After running the command, you\u2019ll see a few prompts that will set the details of the app for you. Let&#8217;s go step by step:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Name your app.<\/li>\n\n\n\n<li>Enable app router.<\/li>\n<\/ol>\n\n\n\n<p>The other steps are optional and entirely up to you. In my case, I chose to use TypeScript and Tailwind CSS as well.<\/p>\n\n\n\n<p>Afterwards, we\u2019ll need to install our Cloudinary package for easy Cloudinary integration in our app:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">npm install next-cloudinary<\/code><\/span><\/pre>\n\n\n<p>We\u2019re almost there \u2013 just one more step and we\u2019ll be ready to start hacking! We\u2019ll need to set up some <a href=\"https:\/\/nextjs.org\/docs\/app\/building-your-application\/configuring\/environment-variables\">environment variables<\/a> to help us securely store key information for our app to communicate with Cloudinary:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME<\/strong>. This is your Cloudinary cloud name, a unique identifier for your Cloudinary account. This can be found at the top-right corner of your Cloudinary console.<\/li>\n\n\n\n<li><strong>CLOUDINARY_API_SECRET.<\/strong> The private key used for secure connections with the Cloudinary API.<\/li>\n\n\n\n<li><strong>NEXT_PUBLIC_CLOUDINARY_API_KEY<\/strong>. The public key used to authenticate your requests to the Cloudinary API.<\/li>\n<\/ul>\n\n\n\n<p>You can find your private and public API keys in the <strong>API Keys<\/strong> section on the settings page of your Cloudinary console:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"528\" data-public-id=\"Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-2\/blog-Using-Next.js-to-Upload-Images-2.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_528,c_scale\/f_auto,q_auto\/v1727372168\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-2\/blog-Using-Next.js-to-Upload-Images-2.png?_i=AA\" alt=\"Image showing screenshot of Cloudinary API keys setting up for the next-cloudinary image handling project\" class=\"wp-post-35759 wp-image-35761\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1727372168\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372168\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-2\/blog-Using-Next.js-to-Upload-Images-2.png?_i=AA 1999w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372168\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-2\/blog-Using-Next.js-to-Upload-Images-2.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372168\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-2\/blog-Using-Next.js-to-Upload-Images-2.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372168\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-2\/blog-Using-Next.js-to-Upload-Images-2.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372168\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-2\/blog-Using-Next.js-to-Upload-Images-2.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Uploading Our Images<\/h2>\n\n\n\n<p>Let\u2019s jump straight to why we&#8217;re here: uploading images.<\/p>\n\n\n\n<p>We have two different components to accomplish this goal: <a href=\"https:\/\/next.cloudinary.dev\/clduploadbutton\/basic-usage\">CldUploadButton<\/a> and <a href=\"https:\/\/next.cloudinary.dev\/clduploadwidget\/basic-usage\">CldUploadWidget<\/a>. The button component, as the name suggests, adds a button to our page for easy uploads, whereas the widget component gives you more control over the UI.&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Server Component Caveats<\/h3>\n\n\n\n<p>To render the <code>CldUploadWidget<\/code> component within a Server Component, we\u2019ll need to rely on client components since client-side methods must be passed as props. As a result, this component can\u2019t be directly used as a server component, limiting its ability to function as a first-class server-side element.<\/p>\n\n\n\n<p>Because of the above, for this tutorial, we\u2019ll use the <code>CldUploadButton<\/code> component instead.<\/p>\n\n\n\n<p>Before using this component, though, determine where and how to render it without affecting our tree and bundle. As stated in the <a href=\"https:\/\/react.dev\/reference\/rsc\/use-client#caveats\">React docs<\/a>, we\u2019ll need to specify where our client boundary starts using the \u201cuse client\u201d directive. We don\u2019t need to add multiple \u201cuse client\u201d at the top of the file if we\u2019re already in the client bundle of Next.js; if we\u2019re already importing our component inside the client bundle, adding an extra \u201cuse client\u201d won\u2019t cause additional bundling effects as it\u2019s already part of it.<\/p>\n\n\n\n<p>For this reason, Cloudinary ships its client components without the \u201cuse client\u201d directive by default, so we have the flexibility to choose when and where to start the client-side bundle without adding unnecessary boundaries.<\/p>\n\n\n\n<p>Now, let\u2019s decide where to start our client tree. We have two options:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Mark the entire page as a Client Component using the \u201cuse client\u201d at the top of the file, import our component, and start using it from there. This approach isn\u2019t ideal because it would make the entire component tree client-side.<\/li>\n\n\n\n<li>Create a wrapper that enables this client-side component without affecting the rest of the tree. This approach allows us to progressively enhance the page, rather than rendering it as static HTML\/CSS.<\/li>\n<\/ul>\n\n\n\n<p>Since the second approach is a better solution for our use case, let&#8217;s proceed with that. We&#8217;ll start by setting up the wrapper component.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Building Our Component<\/h3>\n\n\n\n<p>First, navigate to the root of your Next.js app, then go to the app directory and create a new folder named \u201ccomponents\u201d.<\/p>\n\n\n\n<p>Inside this folder, create a new file for our wrapper component and name it \u201c<code>UploadButton.tsx<\/code>\u201d&nbsp;(or just &#8220;<code>jsx<\/code>&#8220;, depending on if you chose typescript, or not). This component will utilize the <code>next-cloudinary<\/code> package to render the button that we need for uploading images in Cloudinary.<\/p>\n\n\n\n<p><code>UploadButton.tsx<\/code>, our wrapper component, is where we\u2019ll import and use the Cloudinary upload button. It will look like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-string\">\"use client\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { CldUploadButton, type CldUploadButtonProps } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next-cloudinary\"<\/span>;\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">UploadButton<\/span>(<span class=\"hljs-params\">props: CldUploadButtonProps<\/span>) <\/span>{\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">CldUploadButton<\/span> {<span class=\"hljs-attr\">...props<\/span>} \/&gt;<\/span><\/span>;\n\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> UploadButton;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now, if we render this component in our <code>page.tsx<\/code> component, we can import this component and start using it. I also added basic styles to the button:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> UploadButton <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@\/app\/components\/UploadButton\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Home<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> (\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">UploadButton<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span><\/span>\n\n\u00a0\u00a0);\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You&#8217;ll see a button with the text <strong>Upload<\/strong>. When you click it, the Upload widget will open. However, uploading an image won&#8217;t work just yet. We\u2019ll need to make some adjustments first.<\/p>\n\n\n\n<p>We have two different ways of uploading our images using our button: Signed and Unsigned methods. The difference is that Unsigned lets us upload images without any authentication, like our API secret, for example. It has its use cases, like public social media sites with no moderations or event-based application where users need to quickly share photos of an event happening, but for the most part, we want to make sure and have more control over what is uploaded to our Cloudinary account for safety reasons, so we\u2019ll go with the signed workflow.<\/p>\n\n\n\n<p>Our flow will work by having a new endpoint that\u2019s triggered when we upload an image. This endpoint will return a signature token, which we&#8217;ll then use to complete the image upload process.<\/p>\n\n\n\n<p>Let&#8217;s create our endpoint. We&#8217;ll be using <a href=\"https:\/\/nextjs.org\/docs\/app\/building-your-application\/routing\/route-handlers\">Route Handlers<\/a> from Next.js. Inside our <code>app<\/code> folder, we&#8217;ll create an <code>api<\/code> folder, and within that, we&#8217;ll add a new folder called &#8220;<code>sign-cloudinary-params<\/code>&#8220;. Then, we&#8217;ll create a <code>route.ts<\/code> file inside this folder.&nbsp;<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">app\n\n\u00a0\u21b3api\n\n\u00a0\u00a0\u21b3sign-cloudinary-params\n\n\u00a0\u00a0\u00a0\u21b3route.ts <span class=\"hljs-comment\">\/\/create this file<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>route.ts<\/code> file will contain the following code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { v2 <span class=\"hljs-keyword\">as<\/span> cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"cloudinary\"<\/span>;\n\n<span class=\"hljs-comment\">\/\/ Config our cloudinary instance<\/span>\n\ncloudinary.config({\n\n\u00a0\u00a0<span class=\"hljs-attr\">cloud_name<\/span>: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,\n\n\u00a0\u00a0<span class=\"hljs-attr\">api_key<\/span>: process.env.NEXT_PUBLIC_CLOUDINARY_API_KEY,\n\n\u00a0\u00a0<span class=\"hljs-attr\">api_secret<\/span>: process.env.CLOUDINARY_API_SECRET,\n\n});\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">POST<\/span>(<span class=\"hljs-params\">request: Request<\/span>) <\/span>{\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> body = <span class=\"hljs-keyword\">await<\/span> request.json();\n\n\u00a0\u00a0<span class=\"hljs-comment\">\/\/ Get the params to sign from the request body.<\/span>\n\n\u00a0\u00a0<span class=\"hljs-comment\">\/\/ This is something that we don't need to worry about as it will come<\/span>\n\n\u00a0\u00a0<span class=\"hljs-comment\">\/\/ from the upload widget<\/span>\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> { paramsToSign } = body;\n\n\u00a0\u00a0<span class=\"hljs-comment\">\/\/ Get the signature with the api_sign_request method, passing the params to sign and the api secret<\/span>\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> signature = cloudinary.utils.api_sign_request(\n\n\u00a0\u00a0\u00a0\u00a0paramsToSign,\n\n\u00a0\u00a0\u00a0\u00a0process.env.CLOUDINARY_API_SECRET <span class=\"hljs-keyword\">as<\/span> string\n\n\u00a0\u00a0);\n\n\u00a0\u00a0<span class=\"hljs-comment\">\/\/ Return the signature<\/span>\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> Response.json({ signature });\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Here, we\u2019re passing the <code>params to sign<\/code> from the request and using the <code>api_sign_request<\/code> method to get our signature token.<\/p>\n\n\n\n<p>So now, to use this endpoint with our button, we\u2019ll pass a new prop inside our component: <code>signatureEndpoint<\/code>. In this prop, we\u2019ll specify the endpoint that we just created:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">import UploadButton from <span class=\"hljs-string\">\"@\/app\/components\/UploadButton\"<\/span>;\n\nexport <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Home<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> (\n\n\u00a0\u00a0\u00a0\u00a0&lt;main&gt;\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;UploadButton\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-comment\">\/\/ The signatureEndpoint prop is the path to the route that will sign the Cloudinary params<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0signatureEndpoint=<span class=\"hljs-string\">\"\/api\/sign-cloudinary-params\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0className=<span class=\"hljs-string\">\"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;\n\n\u00a0\u00a0\u00a0\u00a0&lt;\/main&gt;\n\n\u00a0\u00a0);\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>And that should be it! Now if we try uploading an image with our button again, we should be able to upload it. For this example, I prepared some photos of Japan!<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"890\" height=\"706\" data-public-id=\"Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-4\/blog-Using-Next.js-to-Upload-Images-4.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_890,h_706,c_scale\/f_auto,q_auto\/v1727372173\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-4\/blog-Using-Next.js-to-Upload-Images-4.png?_i=AA\" alt=\"Image showing screenshot of Cloudinary image upload environment with image of a city scape setting up for the next cloudinary image handling project\" class=\"wp-post-35759 wp-image-35763\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1727372173\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372173\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-4\/blog-Using-Next.js-to-Upload-Images-4.png?_i=AA 890w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372173\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-4\/blog-Using-Next.js-to-Upload-Images-4.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372173\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-4\/blog-Using-Next.js-to-Upload-Images-4.png?_i=AA 768w\" sizes=\"auto, (max-width: 890px) 100vw, 890px\" \/><\/figure>\n\n\n\n<p>Now, if we go to our Cloudinary account, we\u2019ll see the photo in our Media Library:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"553\" data-public-id=\"Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-5\/blog-Using-Next.js-to-Upload-Images-5.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_553,c_scale\/f_auto,q_auto\/v1727372233\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-5\/blog-Using-Next.js-to-Upload-Images-5.png?_i=AA\" alt=\"Image showing screenshot of Cloudinary media library environment with image of a city scape setting up for the next cloudinary image handling project\" class=\"wp-post-35759 wp-image-35764\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1727372233\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372233\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-5\/blog-Using-Next.js-to-Upload-Images-5.png?_i=AA 2000w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372233\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-5\/blog-Using-Next.js-to-Upload-Images-5.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372233\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-5\/blog-Using-Next.js-to-Upload-Images-5.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372233\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-5\/blog-Using-Next.js-to-Upload-Images-5.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372233\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-5\/blog-Using-Next.js-to-Upload-Images-5.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Let&#8217;s improve this upload flow even more, shall we? Wouldn&#8217;t it be neat to organize these photos instead of just storing them all in one place? Or to get a specific set of images? Depending on our needs, we might want to retrieve specific images from our library and also add some moderation; we don\u2019t want any images in there. To achieve this, we&#8217;ll use <a href=\"https:\/\/support.cloudinary.com\/hc\/en-us\/articles\/360016481620-What-are-Upload-presets-and-how-to-use-them\">Upload Presets<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Improving Our Upload Flow by Using Upload Presets<\/h2>\n\n\n\n<p>In our Cloudinary account, click <strong>Settings<\/strong> (the cog on the bottom left), <strong>Upload Presets<\/strong>, and then <strong>Add Upload Preset<\/strong>:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"537\" data-public-id=\"Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-6\/blog-Using-Next.js-to-Upload-Images-6.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_537,c_scale\/f_auto,q_auto\/v1727372179\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-6\/blog-Using-Next.js-to-Upload-Images-6.png?_i=AA\" alt=\"Image showing screenshot of Cloudinary upload preset environment setting up for the next cloudinary image handling project\" class=\"wp-post-35759 wp-image-35765\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1727372179\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372179\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-6\/blog-Using-Next.js-to-Upload-Images-6.png?_i=AA 2000w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372179\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-6\/blog-Using-Next.js-to-Upload-Images-6.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372179\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-6\/blog-Using-Next.js-to-Upload-Images-6.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372179\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-6\/blog-Using-Next.js-to-Upload-Images-6.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372179\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-6\/blog-Using-Next.js-to-Upload-Images-6.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>We can create a preset that will be used to group images containing \u201ccities\u201d:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"787\" height=\"534\" data-public-id=\"Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-7\/blog-Using-Next.js-to-Upload-Images-7.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_787,h_534,c_scale\/f_auto,q_auto\/v1727372184\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-7\/blog-Using-Next.js-to-Upload-Images-7.png?_i=AA\" alt=\"Image showing screenshot of Cloudinary preset environment setting up for the next cloudinary image handling project\" class=\"wp-post-35759 wp-image-35766\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1727372184\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372184\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-7\/blog-Using-Next.js-to-Upload-Images-7.png?_i=AA 787w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372184\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-7\/blog-Using-Next.js-to-Upload-Images-7.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372184\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-7\/blog-Using-Next.js-to-Upload-Images-7.png?_i=AA 768w\" sizes=\"auto, (max-width: 787px) 100vw, 787px\" \/><\/figure>\n\n\n\n<p>The other options are fine as is, we want these images to be signed as explained above, and the overwriting is also helpful in case we upload an image with the same public ID that already exists in our Media Library. The public ID is a unique string generated when an asset is uploaded to Cloudinary. If the <strong>Use filename or externally defined Public ID<\/strong> option is enabled, the public ID will match the file&#8217;s name. If this option is disabled, the public ID will be automatically generated as a random string of characters. Enabling the overwrite ensures that if we upload an image with the same public ID, it replaces the old one.<\/p>\n\n\n\n<p>I also set a folder name so that all images saved with this preset go into the \u201ccities\u201d folder.<\/p>\n\n\n\n<p>I\u2019d like to add an extra functionality to this preset. Go to the <strong>Transform<\/strong> tab. Here, we can apply <a href=\"https:\/\/cloudinary.com\/documentation\/transformations_intro\">transformations to our assets<\/a> like round borders, background removal, and more, but for this demo, let\u2019s add a transformation that resizes our image to a fixed size when uploading them, just like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img width=\"854\" height=\"737\" data-public-id=\"Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-8\/blog-Using-Next.js-to-Upload-Images-8.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_854,h_737,c_scale\/f_auto,q_auto\/v1727372228\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-8\/blog-Using-Next.js-to-Upload-Images-8.png?_i=AA\" alt=\"Image showing screenshot of Cloudinary image transform environment setting up for the next cloudinary image handling project\" class=\"wp-post-35759 wp-image-35767\" style=\"width:840px;height:auto\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1727372228\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372228\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-8\/blog-Using-Next.js-to-Upload-Images-8.png?_i=AA 854w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372228\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-8\/blog-Using-Next.js-to-Upload-Images-8.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372228\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-8\/blog-Using-Next.js-to-Upload-Images-8.png?_i=AA 768w\" sizes=\"auto, (max-width: 854px) 100vw, 854px\" \/><\/figure>\n\n\n\n<p>We could also add more configurations for these assets, like adding tags, allowing only specific formats, changing the format of the assets, and more.<\/p>\n\n\n\n<p>Once we\u2019re ready with our configuration, click <strong>Save<\/strong>.<\/p>\n\n\n\n<p>Then, let&#8217;s go to the <strong>Upload<\/strong> tab to find the preset we created:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"997\" data-public-id=\"Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-9\/blog-Using-Next.js-to-Upload-Images-9.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_997,c_scale\/f_auto,q_auto\/v1727372189\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-9\/blog-Using-Next.js-to-Upload-Images-9.png?_i=AA\" alt=\"Image showing screenshot of Cloudinary upload preset environment enabling pre-sign for the next-cloudinary image handling project\" class=\"wp-post-35759 wp-image-35768\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1727372189\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372189\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-9\/blog-Using-Next.js-to-Upload-Images-9.png?_i=AA 1268w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372189\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-9\/blog-Using-Next.js-to-Upload-Images-9.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372189\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-9\/blog-Using-Next.js-to-Upload-Images-9.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372189\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-9\/blog-Using-Next.js-to-Upload-Images-9.png?_i=AA 1024w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Inside our preset, select the <strong>Upload Control<\/strong> tab and the <strong>Manual<\/strong> checkbox in the <strong>Auto moderation<\/strong> section. This means that every time an asset is uploaded with this preset, it will first need to pass manual moderation before the image is available for display.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"514\" data-public-id=\"Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-10\/blog-Using-Next.js-to-Upload-Images-10.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_514,c_scale\/f_auto,q_auto\/v1727372221\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-10\/blog-Using-Next.js-to-Upload-Images-10.png?_i=AA\" alt=\"Image showing screenshot of Cloudinary upload preset environment enabling manual moderation for the next-cloudinary image handling project\" class=\"wp-post-35759 wp-image-35769\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1727372221\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372221\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-10\/blog-Using-Next.js-to-Upload-Images-10.png?_i=AA 2000w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372221\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-10\/blog-Using-Next.js-to-Upload-Images-10.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372221\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-10\/blog-Using-Next.js-to-Upload-Images-10.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372221\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-10\/blog-Using-Next.js-to-Upload-Images-10.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372221\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-10\/blog-Using-Next.js-to-Upload-Images-10.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>We could add auto-moderation to these assets via one of these options, making an advanced algorithm to make decisions. These are useful when we need to moderate a large volume of uploads and want to ensure consistency, but for now, let\u2019s stick with manual moderation as we don\u2019t have a large volume of uploads and so we have more control over what gets uploaded. We can also add more strict moderation settings, like specifying which proxy these assets need to come from or the allowed formats of the assets.<\/p>\n\n\n\n<p>Let\u2019s save these new settings and add the new preset to our button:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> UploadButton <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@\/app\/components\/UploadButton\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Home<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> (\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">UploadButton<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">signatureEndpoint<\/span>=<span class=\"hljs-string\">\"\/api\/sign-cloudinary-params\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ <span class=\"hljs-attr\">The<\/span> <span class=\"hljs-attr\">uploadPreset<\/span> <span class=\"hljs-attr\">prop<\/span> <span class=\"hljs-attr\">is<\/span> <span class=\"hljs-attr\">the<\/span> <span class=\"hljs-attr\">name<\/span> <span class=\"hljs-attr\">of<\/span> <span class=\"hljs-attr\">the<\/span> <span class=\"hljs-attr\">upload<\/span> <span class=\"hljs-attr\">preset<\/span> <span class=\"hljs-attr\">that<\/span> <span class=\"hljs-attr\">we<\/span> <span class=\"hljs-attr\">created<\/span> <span class=\"hljs-attr\">in<\/span> <span class=\"hljs-attr\">Cloudinary<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">uploadPreset<\/span>=<span class=\"hljs-string\">\"cities\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span><\/span>\n\n\u00a0\u00a0);\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now, if we upload new images and check our media, the image will be stored in the folder that we specified before:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"534\" data-public-id=\"Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-11\/blog-Using-Next.js-to-Upload-Images-11.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_534,c_scale\/f_auto,q_auto\/v1727372196\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-11\/blog-Using-Next.js-to-Upload-Images-11.png?_i=AA\" alt=\"Image showing screenshot of Cloudinary media library environment with multiple pictures of cityscapes for the next cloudinary image handling project\" class=\"wp-post-35759 wp-image-35770\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1727372196\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372196\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-11\/blog-Using-Next.js-to-Upload-Images-11.png?_i=AA 1999w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372196\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-11\/blog-Using-Next.js-to-Upload-Images-11.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372196\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-11\/blog-Using-Next.js-to-Upload-Images-11.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372196\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-11\/blog-Using-Next.js-to-Upload-Images-11.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372196\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-11\/blog-Using-Next.js-to-Upload-Images-11.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>When we click the <strong>Moderation<\/strong> tab, the image will be pending our moderation approval. If we decline, it will be erased. If we approve, it will proceed, and we\u2019ll be able to access this asset and display it in our app.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"512\" data-public-id=\"Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-12\/blog-Using-Next.js-to-Upload-Images-12.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_512,c_scale\/f_auto,q_auto\/v1727372216\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-12\/blog-Using-Next.js-to-Upload-Images-12.png?_i=AA\" alt=\"Image showing screenshot of Cloudinary media library environment with multiple pictures of cityscapes showing manual moderation functionality for the next cloudinary image handling project\" class=\"wp-post-35759 wp-image-35771\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1727372216\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372216\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-12\/blog-Using-Next.js-to-Upload-Images-12.png?_i=AA 1999w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372216\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-12\/blog-Using-Next.js-to-Upload-Images-12.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372216\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-12\/blog-Using-Next.js-to-Upload-Images-12.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372216\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-12\/blog-Using-Next.js-to-Upload-Images-12.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372216\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-12\/blog-Using-Next.js-to-Upload-Images-12.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Also, notice how our transformation is working perfectly! All of our images now have the fixed size that we specified.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Tagging Upload Presets<\/h3>\n\n\n\n<p>Before going to the next section, let\u2019s say that we don\u2019t have just one city, but multiple. Tagging these images would be helpful to distinguish between them. In our <code>UploadButton<\/code> component, pass a new \u201coptions\u201d prop where we can specify tags to be added to our assets once we upload them:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">&lt;UploadButton\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-comment\">\/\/ The signatureEndpoint prop is the path to the route that will sign the Cloudinary params<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0signatureEndpoint=<span class=\"hljs-string\">\"\/api\/sign-cloudinary-params\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0className=<span class=\"hljs-string\">\"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-comment\">\/\/ The uploadPreset prop is the name of the upload preset that we created in Cloudinary<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0uploadPreset=<span class=\"hljs-string\">\"cities\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0options={{\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0tags: &#91;<span class=\"hljs-string\">\"tokyo\"<\/span>],\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}}\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now, if we upload a new image and check its metadata, it should have the tag we specified:&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"505\" data-public-id=\"Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-13\/blog-Using-Next.js-to-Upload-Images-13.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_505,c_scale\/f_auto,q_auto\/v1727372211\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-13\/blog-Using-Next.js-to-Upload-Images-13.png?_i=AA\" alt=\"Image showing screenshot of Cloudinary media library environment with picture of city lights showing updated image metadata for the next cloudinary image handling project\" class=\"wp-post-35759 wp-image-35772\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1727372211\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372211\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-13\/blog-Using-Next.js-to-Upload-Images-13.png?_i=AA 1999w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372211\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-13\/blog-Using-Next.js-to-Upload-Images-13.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372211\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-13\/blog-Using-Next.js-to-Upload-Images-13.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372211\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-13\/blog-Using-Next.js-to-Upload-Images-13.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372211\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-13\/blog-Using-Next.js-to-Upload-Images-13.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Our \u201cUpload Preset\u201d configuration and tags are ready! Let\u2019s proceed to the next step: retrieving these images dynamically from our App!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Retrieving Images in Our Server Component<\/h2>\n\n\n\n<p>To retrieve our images, we\u2019ll use our Cloudinary SDK. To avoid instantiating the Cloudinary SDK every time we need it, let&#8217;s create a new utility function to handle this for us. In our app folder, create a new folder called \u201cutils\u201d and inside it, add the file \u201cgetCloudinary\u201d and write the following code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { v2 <span class=\"hljs-keyword\">as<\/span> cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"cloudinary\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getCloadinary<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\n\u00a0\u00a0<span class=\"hljs-comment\">\/\/ Config our Cloudinary instance<\/span>\n\n\u00a0\u00a0cloudinary.config({\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">cloud_name<\/span>: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">api_key<\/span>: process.env.NEXT_PUBLIC_CLOUDINARY_API_KEY,\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">api_secret<\/span>: process.env.CLOUDINARY_API_SECRET,\n\n\u00a0\u00a0});\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> cloudinary;\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Let\u2019s use it in our Server Component and use one of their APIs to retrieve the images in the folder that we need:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">import UploadButton from <span class=\"hljs-string\">\"@\/app\/components\/UploadButton\"<\/span>;\n\nimport getCloudinary from <span class=\"hljs-string\">\"@\/app\/utils\/getCloudinary\"<\/span>;\n\n<span class=\"hljs-comment\">\/\/ Cloudinary client<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> cloudinary = getCloudinary();\n\nexport <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Home<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n\n\u00a0\u00a0<span class=\"hljs-comment\">\/\/ Get all the resources from the \"cities\" folder and the ones that have the \"tokyo\" tag<\/span>\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> { resources } = await cloudinary.search.expression(<span class=\"hljs-string\">\"folder=cities AND tags=tokyo\"<\/span>).execute();\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> (\n\n\u00a0\u00a0\u00a0\u00a0&lt;main&gt;\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;UploadButton\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-comment\">\/\/ The signatureEndpoint prop is the path to the route that will sign the Cloudinary params<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0signatureEndpoint=<span class=\"hljs-string\">\"\/api\/sign-cloudinary-params\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0className=<span class=\"hljs-string\">\"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-comment\">\/\/ The uploadPreset prop is the name of the upload preset that we created in Cloudinary<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0uploadPreset=<span class=\"hljs-string\">\"cities\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;\n\n\u00a0\u00a0\u00a0\u00a0&lt;\/main&gt;\n\n\u00a0\u00a0);\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>CldImage<\/code> component from <code>next-cloudinary<\/code> will unlock the Cloudinary&#8217;s full potential so let&#8217;s use it to display our images. Just as we did with our <code>&lt;UploadButton\/&gt;<\/code>, create a wrapper for this component:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ app\/components\/CldImage.tsx<\/span>\n\n<span class=\"hljs-string\">\"use client\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { CldImage <span class=\"hljs-keyword\">as<\/span> CldImageDefault, CldImageProps } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next-cloudinary\"<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> CldImage = <span class=\"hljs-function\">(<span class=\"hljs-params\">props: CldImageProps<\/span>) =&gt;<\/span> {\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">CldImageDefault<\/span> {<span class=\"hljs-attr\">...props<\/span>} \/&gt;<\/span><\/span>;\n\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> CldImage;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Next, we\u2019ll import it in our <code>page.tsx<\/code> component and start displaying our images! I added some styles to my component, but feel free to add your own:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> UploadButton <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@\/app\/components\/UploadButton\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> getCloudinary <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@\/app\/utils\/getCloudinary\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> CldImage <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@\/app\/components\/CldImage\"<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> cloudinary = getCloudinary();\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Home<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\n\u00a0\u00a0<span class=\"hljs-comment\">\/\/ Get all the images from the \"cties\" folder and the ones that have the \"tokyo\" tag<\/span>\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> { resources } = <span class=\"hljs-keyword\">await<\/span> cloudinary.search\n\n\u00a0\u00a0\u00a0\u00a0.expression(<span class=\"hljs-string\">\"folder=cities AND tags=tokyo\"<\/span>)\n\n\u00a0\u00a0\u00a0\u00a0.execute();\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> (\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">section<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex flex-col gap-10 mt-10 items-center min-h-screen\"<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">UploadButton<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ <span class=\"hljs-attr\">The<\/span> <span class=\"hljs-attr\">signatureEndpoint<\/span> <span class=\"hljs-attr\">prop<\/span> <span class=\"hljs-attr\">is<\/span> <span class=\"hljs-attr\">the<\/span> <span class=\"hljs-attr\">path<\/span> <span class=\"hljs-attr\">to<\/span> <span class=\"hljs-attr\">the<\/span> <span class=\"hljs-attr\">route<\/span> <span class=\"hljs-attr\">that<\/span> <span class=\"hljs-attr\">will<\/span> <span class=\"hljs-attr\">sign<\/span> <span class=\"hljs-attr\">the<\/span> <span class=\"hljs-attr\">Cloudinary<\/span> <span class=\"hljs-attr\">params<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">signatureEndpoint<\/span>=<span class=\"hljs-string\">\"\/api\/sign-cloudinary-params\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ <span class=\"hljs-attr\">The<\/span> <span class=\"hljs-attr\">uploadPreset<\/span> <span class=\"hljs-attr\">prop<\/span> <span class=\"hljs-attr\">is<\/span> <span class=\"hljs-attr\">the<\/span> <span class=\"hljs-attr\">name<\/span> <span class=\"hljs-attr\">of<\/span> <span class=\"hljs-attr\">the<\/span> <span class=\"hljs-attr\">upload<\/span> <span class=\"hljs-attr\">preset<\/span> <span class=\"hljs-attr\">that<\/span> <span class=\"hljs-attr\">we<\/span> <span class=\"hljs-attr\">created<\/span> <span class=\"hljs-attr\">in<\/span> <span class=\"hljs-attr\">Cloudinary<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">uploadPreset<\/span>=<span class=\"hljs-string\">\"cities\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">options<\/span>=<span class=\"hljs-string\">{{<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">tags:<\/span> &#91;\"<span class=\"hljs-attr\">tokyo<\/span>\"],\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}}\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"grid grid-cols-3 gap-4\"<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{resources.map((image: CldImage) =&gt; (\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{image.public_id}<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">CldImage<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"max-w-sm overflow-hidden shadow-lg\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">{image.public_id}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{image.secure_url}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">{500}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">{500}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0))}\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">section<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span><\/span>\n\n\u00a0\u00a0);\n\n}\n\ntype CldImage = {\n\n\u00a0\u00a0<span class=\"hljs-attr\">public_id<\/span>: string;\n\n\u00a0\u00a0secure_url: string;\n\n\u00a0\u00a0width: number;\n\n\u00a0\u00a0height: number;\n\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<figure class=\"wp-block-image size-large\"><img width=\"1024\" height=\"621\" data-public-id=\"Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-14\/blog-Using-Next.js-to-Upload-Images-14.png\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/w_1024,h_621,c_scale\/f_auto,q_auto\/v1727372207\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-14\/blog-Using-Next.js-to-Upload-Images-14.png?_i=AA\" alt=\"Image showing screenshot of Cloudinary upload environment with image of shinto temple rising above a distant city for the next-cloudinary image handling project\" class=\"wp-post-35759 wp-image-35773\" data-format=\"png\" data-transformations=\"f_auto,q_auto\" data-version=\"1727372207\" data-seo=\"1\" srcset=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372207\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-14\/blog-Using-Next.js-to-Upload-Images-14.png?_i=AA 2000w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372207\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-14\/blog-Using-Next.js-to-Upload-Images-14.png?_i=AA 300w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372207\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-14\/blog-Using-Next.js-to-Upload-Images-14.png?_i=AA 768w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372207\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-14\/blog-Using-Next.js-to-Upload-Images-14.png?_i=AA 1024w, https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1727372207\/Web_Assets\/blog\/blog-Using-Next.js-to-Upload-Images-14\/blog-Using-Next.js-to-Upload-Images-14.png?_i=AA 1536w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>And we\u2019re done! We can now display the images that we\u2019ve approved in our moderation list.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>In this flow, we created a component to dynamically upload our images to Cloudinary, added tags to these assets, and configured them through our custom Upload Preset to transform, moderate, and organize them. We also displayed these images easily in our Next.js app using Server Components.<\/p>\n\n\n\n<p>We\u2019ve just scratched the surface of what Cloudinary offers for uploading and displaying images. There are many more features to explore, such as auto transformation, auto moderation, and more advanced settings. <a href=\"https:\/\/cloudinary.com\/\">Sign up<\/a> for a free account today.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this blog post, we&#8217;ll show you how to upload images with a single button, store them in specific folders, enable manual moderation, and display these images in your app filtered by tags \u2013 all by using Next.js. First, we\u2019ll need to set up the following: Once we have our Cloudinary account and images ready, [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":35775,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[165,203,212,373],"class_list":["post-35759","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-image-transformation","tag-moderation","tag-next-js","tag-upload"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>How to Use Next.js and Cloudinary to Upload, Transform, and Moderate Your Images<\/title>\n<meta name=\"description\" content=\"In this article, you\u2019ll learn how to use Next.JS with Cloudinary to upload images with a single button, enable manual moderation, and more.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using Next.js and Cloudinary to Upload, Transform, and Moderate Your Images\" \/>\n<meta property=\"og:description\" content=\"In this article, you\u2019ll learn how to use Next.JS with Cloudinary to upload images with a single button, enable manual moderation, and more.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-09-26T14:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-10-22T20:44:58+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1726871123\/nextjs_upload-presets-blog\/nextjs_upload-presets-blog.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Using Next.js and Cloudinary to Upload, Transform, and Moderate Your Images\",\"datePublished\":\"2024-09-26T14:00:00+00:00\",\"dateModified\":\"2025-10-22T20:44:58+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images\"},\"wordCount\":2102,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1726871123\/nextjs_upload-presets-blog\/nextjs_upload-presets-blog.jpg?_i=AA\",\"keywords\":[\"Image Transformation\",\"Moderation\",\"Next.js\",\"Upload\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2024\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images\",\"url\":\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images\",\"name\":\"How to Use Next.js and Cloudinary to Upload, Transform, and Moderate Your Images\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1726871123\/nextjs_upload-presets-blog\/nextjs_upload-presets-blog.jpg?_i=AA\",\"datePublished\":\"2024-09-26T14:00:00+00:00\",\"dateModified\":\"2025-10-22T20:44:58+00:00\",\"description\":\"In this article, you\u2019ll learn how to use Next.JS with Cloudinary to upload images with a single button, enable manual moderation, and more.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1726871123\/nextjs_upload-presets-blog\/nextjs_upload-presets-blog.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1726871123\/nextjs_upload-presets-blog\/nextjs_upload-presets-blog.jpg?_i=AA\",\"width\":2000,\"height\":1100,\"caption\":\"Image showing city lights and graphic representation of next-cloudinary code\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using Next.js and Cloudinary to Upload, Transform, and Moderate Your Images\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to Use Next.js and Cloudinary to Upload, Transform, and Moderate Your Images","description":"In this article, you\u2019ll learn how to use Next.JS with Cloudinary to upload images with a single button, enable manual moderation, and more.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images","og_locale":"en_US","og_type":"article","og_title":"Using Next.js and Cloudinary to Upload, Transform, and Moderate Your Images","og_description":"In this article, you\u2019ll learn how to use Next.JS with Cloudinary to upload images with a single button, enable manual moderation, and more.","og_url":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images","og_site_name":"Cloudinary Blog","article_published_time":"2024-09-26T14:00:00+00:00","article_modified_time":"2025-10-22T20:44:58+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1726871123\/nextjs_upload-presets-blog\/nextjs_upload-presets-blog.jpg?_i=AA","type":"image\/jpeg"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Using Next.js and Cloudinary to Upload, Transform, and Moderate Your Images","datePublished":"2024-09-26T14:00:00+00:00","dateModified":"2025-10-22T20:44:58+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images"},"wordCount":2102,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1726871123\/nextjs_upload-presets-blog\/nextjs_upload-presets-blog.jpg?_i=AA","keywords":["Image Transformation","Moderation","Next.js","Upload"],"inLanguage":"en-US","copyrightYear":"2024","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images","url":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images","name":"How to Use Next.js and Cloudinary to Upload, Transform, and Moderate Your Images","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1726871123\/nextjs_upload-presets-blog\/nextjs_upload-presets-blog.jpg?_i=AA","datePublished":"2024-09-26T14:00:00+00:00","dateModified":"2025-10-22T20:44:58+00:00","description":"In this article, you\u2019ll learn how to use Next.JS with Cloudinary to upload images with a single button, enable manual moderation, and more.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1726871123\/nextjs_upload-presets-blog\/nextjs_upload-presets-blog.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1726871123\/nextjs_upload-presets-blog\/nextjs_upload-presets-blog.jpg?_i=AA","width":2000,"height":1100,"caption":"Image showing city lights and graphic representation of next-cloudinary code"},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/next-js-cloudinary-upload-transform-moderate-images#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Using Next.js and Cloudinary to Upload, Transform, and Moderate Your Images"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1726871123\/nextjs_upload-presets-blog\/nextjs_upload-presets-blog.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/35759","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=35759"}],"version-history":[{"count":5,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/35759\/revisions"}],"predecessor-version":[{"id":38976,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/35759\/revisions\/38976"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/35775"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=35759"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=35759"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=35759"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}