{"id":31473,"date":"2023-10-16T07:00:00","date_gmt":"2023-10-16T14:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=31473"},"modified":"2025-04-16T13:19:29","modified_gmt":"2025-04-16T20:19:29","slug":"uploading-images-videos-next-js-server-side-multer-xata","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata","title":{"rendered":"Uploading Images and Videos to Cloudinary Using Next.js Server-Side, Multer, and Xata Database"},"content":{"rendered":"\n<p>It may not be surprising that you&#8217;ve already uploaded a file today, whether it will disappear after a time or be stored in an online database. So, it&#8217;s become imperative to create applications enabling file uploads. Using Next.js server-side, you can implement this.<\/p>\n\n\n\n<p>In this blog post, we&#8217;ll discuss the frontend, what our project does, and the tools we need.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/image-and-video-upload-to-cloudinary-using-nextjs-server-side-multer-and-xata-database-3l9f#what-we-are-building\"><\/a>What We&#8217;re Building<\/h2>\n\n\n\n<p>The project is a digital flashcard for memorizing. A physical flashcard has a front and a back; the front poses a question, and the reverse offers the solution. A digital flashcard allows us to add images and videos to help us better remember things.<\/p>\n\n\n\n<p>The advantages of a flashcard are listed below.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>It aids in enhancing visual memory.<\/li>\n\n\n\n<li>It promotes learning and is portable.<\/li>\n\n\n\n<li>For acronyms, mathematical formulas, algorithmic codes, etc., flashcards are instructive.<\/li>\n\n\n\n<li>It&#8217;s affordable.<\/li>\n<\/ul>\n\n\n\n<p>See demo&nbsp;<a href=\"http:\/\/hackmamba-xata-cloudinary-project.vercel.app\/\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p><a href=\"https:\/\/dev.to\/hackmamba\/image-and-video-upload-to-cloudinary-using-nextjs-server-side-multer-and-xata-database-3l9f#github-url\"><\/a><strong>GitHub URL<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-embed\"><div class=\"wp-block-embed__wrapper\">\nhttps:\/\/github.com\/Theodore-Kelechukwu-Onyejiaku\/hackmamba-xata-cloudinary-project\n<\/div><\/figure>\n\n\n\n<p><a href=\"https:\/\/dev.to\/hackmamba\/image-and-video-upload-to-cloudinary-using-nextjs-server-side-multer-and-xata-database-3l9f#live-demo\"><\/a><strong>Live demo<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-embed\"><div class=\"wp-block-embed__wrapper\">\nhttps:\/\/hackmamba-xata-cloudinary-project.vercel.app\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Frontend<\/h2>\n\n\n\n<p>The frontend part of our work deals with how we interact with our project as seen in the live URL shared above. Here are the tools used for the frontend.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Frontend Tools<\/strong><\/h3>\n\n\n\n<p>Using the&nbsp;<code>npm i &lt;tool_name&gt;<\/code>&nbsp;command, we can install them.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code><strong>aos<\/strong><\/code>. This is used for the animation of cards as we scroll down the application.<\/li>\n\n\n\n<li><code><strong>react-icons<\/strong><\/code>. This was used to display icons in our project.<\/li>\n\n\n\n<li><code><strong>react-quill<\/strong><\/code>. This is for the WYSIWYG editor for adding&nbsp;<strong>front<\/strong>&nbsp;and&nbsp;<strong>back<\/strong>&nbsp;content.<\/li>\n\n\n\n<li><code><strong>react-toastify<\/strong><\/code>. This was used for the toast notifications in our app.<\/li>\n\n\n\n<li><strong>Tailwind CSS<\/strong>. This is the main CSS of our application. Please note that other custom CSS was used in the project. Visit the Github URL above to see all.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Frontend Logic<\/strong><\/h3>\n\n\n\n<p>Here&#8217;s the logic of our application.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A user registers by utilizing the Credentials or Github providers (email and password). Look at the file at `pages\/auth\/signup` in the Github URL.<\/li>\n\n\n\n<li>After successful registration, the user is routed to the login page `pages\/auth\/signin`.<\/li>\n\n\n\n<li>After successfully logging in, the user can view all of the cards that other users have made.<\/li>\n\n\n\n<li>We can choose from options like making a card, seeing our collections and cards, searching for a card based on its name or category, switching between dark and light settings, like a card, and watching a video.<\/li>\n\n\n\n<li>The card name, category, image, optional video, and front and back content must all be added before a card can be created.<\/li>\n\n\n\n<li>The user can begin flipping cards to practice memorizing, and films and visuals will assist them to develop their memory.<\/li>\n\n\n\n<li>A user who is the card&#8217;s owner can update or delete the card once it has been created.<\/li>\n\n\n\n<li>A user can add a freshly made card to their collection by clicking the Plus symbol while they are not the owner of it.<\/li>\n\n\n\n<li>There are three options for editing a card. We have the option to only update the card&#8217;s image, video, or other information.<\/li>\n\n\n\n<li>We can search for a card by typing its name or its category into the search box.<\/li>\n<\/ul>\n\n\n\n<p>Below is a High-Level Model of the frontend logic:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--yNWAAXgD--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_13D9629A17BA205412E87FA69ADEF80CA77BC359F9970BA6A590DF17482B2D39_1667844528645_flashcardHLM.drawio.png\"><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--yNWAAXgD--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_13D9629A17BA205412E87FA69ADEF80CA77BC359F9970BA6A590DF17482B2D39_1667844528645_flashcardHLM.drawio.png\" alt=\"HLM for Digital Flashcard Project\"\/><\/a><\/figure>\n\n\n\n<p>Visit the live URL above to see the application.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Backend<\/h2>\n\n\n\n<p>Here&#8217;s how to install and configure Cloudinary.<\/p>\n\n\n\n<p>1. Install Cloudinary.<\/p>\n\n\n\n<p>Run this command:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">npm install cloudinary\n<\/code><\/span><\/pre>\n\n\n<p>2. Create a Cloudinary account.<\/p>\n\n\n\n<p>We need our Cloudinary cloud name, API key, and API secret to proceed. Head over to the <a href=\"https:\/\/cloudinary.com\/?utm_source=hackmamba&amp;utm_campaign=hackmamba-hackathon&amp;utm_medium=hackmamba-blog\" target=\"_blank\" rel=\"noreferrer noopener\">Cloudinary website<\/a>&nbsp;to get these three.<\/p>\n\n\n\n<p>Click the <strong>Dashboard<\/strong> tab. There, we&#8217;ll find our API key, API secret, and cloud name.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--avZwo0oL--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_989AA707FBDB1A6E245B0183CDBE36E7057DC650108E1558D444FCEE5091CDDF_1667441247189_Screen%2BShot%2B2022-11-03%2Bat%2B3.06.15%2BAM.png\"><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--avZwo0oL--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_989AA707FBDB1A6E245B0183CDBE36E7057DC650108E1558D444FCEE5091CDDF_1667441247189_Screen%2BShot%2B2022-11-03%2Bat%2B3.06.15%2BAM.png\" alt=\"Get the Cloud Name, API Key and API Secret of Our Cloudinary Account\"\/><\/a><\/figure>\n\n\n\n<p>Click&nbsp;<strong>Settings<\/strong>, then&nbsp;<strong>Upload.<\/strong>&nbsp;There, you can add presets.<\/p>\n\n\n\n<p>Give the name and folder the value &#8220;flashcard&#8221; and click&nbsp;<strong>Save<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--Q-KAXZJR--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_13D9629A17BA205412E87FA69ADEF80CA77BC359F9970BA6A590DF17482B2D39_1668196350401_Screen%2BShot%2B2022-11-03%2Bat%2B3.13.08%2BAM.png\"><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--Q-KAXZJR--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_13D9629A17BA205412E87FA69ADEF80CA77BC359F9970BA6A590DF17482B2D39_1668196350401_Screen%2BShot%2B2022-11-03%2Bat%2B3.13.08%2BAM.png\" alt=\"Create a Preset on Cloudinary\"\/><\/a><\/figure>\n\n\n\n<p><strong>3. <\/strong>Add Cloudinary details to&nbsp;<code>.env.local<\/code>&nbsp;file.<\/p>\n\n\n\n<p>Create a&nbsp;<code>.env.local<\/code>&nbsp;file and add the following:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">\/\/ .env.local\nCLOUDINARY_API_KEY=<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">our_key<\/span>&gt;<\/span>\nCLOUDINARY_API_SECRET=<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">our_api_secret<\/span>&gt;<\/span>\nCLOUDINARY_NAME=<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">our_cloud_name<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>4. Create a Cloudinary configuration file.<\/p>\n\n\n\n<p>Create a folder in the root of our project called&nbsp;<code>utils<\/code>. Inside it, create a file&nbsp;<code>cloudinary.js<\/code>&nbsp;and add the following code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">import<\/span> <span class=\"hljs-selector-tag\">cloudinary<\/span> <span class=\"hljs-selector-tag\">from<\/span> \"<span class=\"hljs-selector-tag\">cloudinary<\/span>\";\n\n<span class=\"hljs-selector-tag\">cloudinary<\/span><span class=\"hljs-selector-class\">.v2<\/span><span class=\"hljs-selector-class\">.config<\/span>({\n    <span class=\"hljs-attribute\">cloud_name<\/span>: process.env.CLOUDINARY_NAME,\n    api_key: process.env.CLOUDINARY_API_KEY,\n    api_secret: process.env.CLOUDINARY_API_SECRET\n})\n\n<span class=\"hljs-selector-tag\">export<\/span> <span class=\"hljs-selector-tag\">default<\/span> <span class=\"hljs-selector-tag\">cloudinary<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><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<h2 class=\"wp-block-heading\">Installing and Setting Up <strong>Xata<\/strong><\/h2>\n\n\n\n<p>1. Create a Xata account.<\/p>\n\n\n\n<p>Click this&nbsp;<a href=\"https:\/\/app.xata.io\/?utm_source=hackmamba&amp;utm_campaign=hackmamba-hackathon&amp;utm_medium=hackmamba-blog\" target=\"_blank\" rel=\"noreferrer noopener\">link<\/a>&nbsp;to create a Xata account.<\/p>\n\n\n\n<p>2. Create a database and tables.<\/p>\n\n\n\n<p>If you&#8217;re new to Xata on creating tables, please read and visit these links&nbsp;<a href=\"https:\/\/xata.io\/docs\/intro\/getting-started\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/xata.io\/docs\/intro\/getting-started<\/a>&nbsp;and&nbsp;<a href=\"https:\/\/xata.io\/docs\/quickstart\/index\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/xata.io\/docs\/quickstart\/index<\/a>. Now, create a database called&nbsp;&#8220;test&#8221;&nbsp;or &#8220;flashcard&#8221;. After that, create the following tables:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--ACa8FUZm--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_13D9629A17BA205412E87FA69ADEF80CA77BC359F9970BA6A590DF17482B2D39_1667831780673_Screen%2BShot%2B2022-11-07%2Bat%2B3.35.51%2BPM.png\"><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--ACa8FUZm--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_13D9629A17BA205412E87FA69ADEF80CA77BC359F9970BA6A590DF17482B2D39_1667831780673_Screen%2BShot%2B2022-11-07%2Bat%2B3.35.51%2BPM.png\" alt=\"Users Table\"\/><\/a><figcaption class=\"wp-element-caption\">Users table<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--wapigjKC--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_13D9629A17BA205412E87FA69ADEF80CA77BC359F9970BA6A590DF17482B2D39_1667831850926_Screen%2BShot%2B2022-11-07%2Bat%2B3.37.12%2BPM.png\"><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--wapigjKC--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_13D9629A17BA205412E87FA69ADEF80CA77BC359F9970BA6A590DF17482B2D39_1667831850926_Screen%2BShot%2B2022-11-07%2Bat%2B3.37.12%2BPM.png\" alt=\"Cards Table\"\/><\/a><figcaption class=\"wp-element-caption\">Cards table<\/figcaption><\/figure>\n\n\n\n<p>3. Install the Xata database.<\/p>\n\n\n\n<p>Watch the video&nbsp;<a href=\"https:\/\/xata.io\/docs\/quickstart\/building-a-web-app-with-xata-and-nextjs\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>&nbsp;and see this installation documentation, or:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Install Xata CLI:<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">install<\/span> <span class=\"hljs-selector-tag\">-g<\/span> <span class=\"hljs-keyword\">@xata<\/span>\/cli\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><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<ul class=\"wp-block-list\">\n<li>Next, connect with the Xata database:<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">xata auth login\n<\/code><\/span><\/pre>\n\n\n<p>We&#8217;ll choose <strong>Create a new API key in browser<\/strong> when our terminal prompts us. This opens a browser. We&#8217;ll enter the name of our API key.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--b3wUuT4Y--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_13D9629A17BA205412E87FA69ADEF80CA77BC359F9970BA6A590DF17482B2D39_1668194363934_Screen%2BShot%2B2022-11-11%2Bat%2B8.19.09%2BPM.png\"><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--b3wUuT4Y--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_13D9629A17BA205412E87FA69ADEF80CA77BC359F9970BA6A590DF17482B2D39_1668194363934_Screen%2BShot%2B2022-11-11%2Bat%2B8.19.09%2BPM.png\" alt=\"Generating an API key for our Xata CLI\"\/><\/a><\/figure>\n\n\n\n<p>If successful, we&#8217;ll see this on the browser page.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--Jko7q0Gf--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_13D9629A17BA205412E87FA69ADEF80CA77BC359F9970BA6A590DF17482B2D39_1668195045165_Screen%2BShot%2B2022-11-11%2Bat%2B8.30.27%2BPM.png\"><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--Jko7q0Gf--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/paper-attachments.dropboxusercontent.com\/s_13D9629A17BA205412E87FA69ADEF80CA77BC359F9970BA6A590DF17482B2D39_1668195045165_Screen%2BShot%2B2022-11-11%2Bat%2B8.30.27%2BPM.png\" alt=\"Successful Authentication of Xata CLI\"\/><\/a><\/figure>\n\n\n\n<p>A message \u201cAll set! you can now start using Xata\u201d will be displayed on our terminal.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Initialize our project with Xata:<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">xata init\n<\/code><\/span><\/pre>\n\n\n<p>We&#8217;ll choose the following during the terminal prompts;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Select existing database \u201ctest\u201d or \u201cflashcard\u201d.<\/li>\n\n\n\n<li>Select <strong>Generate Javascript code with ES modules<\/strong> for \u201cDo you want to use code generation in our project?&#8221;<\/li>\n\n\n\n<li>Type in &#8220;utils\/xata\u201d for \u201cChoose the output file for the code generator\u201d.<\/li>\n\n\n\n<li>Select \u201cNo\u201d for \u201cDo you want to generate the TypeScript declarations?\u201d.<\/li>\n\n\n\n<li>For \u201cChoose a default development branch (fallback branch)\u201d select \u201cmain\u201d.<\/li>\n\n\n\n<li>Lastly, for \u201cDo you want to create a .gitignore file and ignore the .env file?, select \u201cYes\u201d.<\/li>\n<\/ul>\n\n\n\n<p>Once done, we should see the message, \u201cYou are all set!\u201d<\/p>\n\n\n\n<p>Make sure to select&nbsp;<code>utils\/xata<\/code>&nbsp;as where our Xata Codegen file will reside. If successful, our&nbsp;<code>xata.js<\/code>&nbsp;file should look like this:<\/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\"><span class=\"hljs-keyword\">import<\/span> { buildClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@xata.io\/client'<\/span>;\n<span class=\"hljs-comment\">\/** @typedef { import('.\/types').SchemaTables } SchemaTables *\/<\/span>\n<span class=\"hljs-comment\">\/** @type { SchemaTables } *\/<\/span>\n<span class=\"hljs-keyword\">const<\/span> tables = &#91;\n  {\n    <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'Users'<\/span>,\n    <span class=\"hljs-attr\">columns<\/span>: &#91;\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'username'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span>, <span class=\"hljs-attr\">unique<\/span>: <span class=\"hljs-literal\">true<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'email'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'email'<\/span>, <span class=\"hljs-attr\">unique<\/span>: <span class=\"hljs-literal\">true<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'fullName'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'text'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'password'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'provider'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'profilePicture'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'profilePictureId'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span> },\n    ],\n  },\n  {\n    <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'Cards'<\/span>,\n    <span class=\"hljs-attr\">columns<\/span>: &#91;\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'name'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'image'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'video'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'user'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'link'<\/span>, <span class=\"hljs-attr\">link<\/span>: { <span class=\"hljs-attr\">table<\/span>: <span class=\"hljs-string\">'Users'<\/span> } },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'likes'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'multiple'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'color'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'front'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'text'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'back'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'text'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'video_id'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'video_signature'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'image_id'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'image_signature'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'category'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'string'<\/span> },\n      { <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">'collectors'<\/span>, <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'multiple'<\/span> },\n    ],\n  },\n];\n<span class=\"hljs-comment\">\/** @type { import('@xata.io\/client').ClientConstructor&lt;{}&gt; } *\/<\/span>\n<span class=\"hljs-keyword\">const<\/span> DatabaseClient = buildClient();\n<span class=\"hljs-keyword\">const<\/span> defaultOptions = {\n  <span class=\"hljs-attr\">databaseURL<\/span>:\n    <span class=\"hljs-string\">'https:\/\/Theodore-Kelechukwu-Onyejiaku-s-workspace-4666kh.eu-west-1.xata.sh\/db\/test'<\/span>,\n};\n<span class=\"hljs-comment\">\/** @typedef { import('.\/types').DatabaseSchema } DatabaseSchema *\/<\/span>\n<span class=\"hljs-comment\">\/** @extends DatabaseClient&lt;DatabaseSchema&gt; *\/<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">XataClient<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">DatabaseClient<\/span> <\/span>{\n  <span class=\"hljs-keyword\">constructor<\/span>(options) {\n    <span class=\"hljs-keyword\">super<\/span>({ ...defaultOptions, ...options }, tables);\n  }\n}\n<span class=\"hljs-keyword\">let<\/span> instance;\n<span class=\"hljs-comment\">\/** @type { () =&gt; XataClient } *\/<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> getXataClient = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">if<\/span> (instance) <span class=\"hljs-keyword\">return<\/span> instance;\n  instance = <span class=\"hljs-keyword\">new<\/span> XataClient();\n  <span class=\"hljs-keyword\">return<\/span> instance;\n};\n<\/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<h2 class=\"wp-block-heading\"><strong>Uploading Images and Video<\/strong>s<\/h2>\n\n\n\n<p>Since this will be done on the Next.js server side, the following packages are to be installed:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">npm i bcrypt datauri multer next-auth next-connect\n<\/code><\/span><\/pre>\n\n\n<ul class=\"wp-block-list\">\n<li><code>bcrypt<\/code>. This will help in authentication, hashing of passwords, and verification.<\/li>\n\n\n\n<li><code>datauri<\/code>. This will help us convert parsed files (image and video) to base 64 encodings.<\/li>\n\n\n\n<li><code>multer<\/code>. This will help us parse the request body.<\/li>\n\n\n\n<li><code>next-auth<\/code>. This will add authentication.<\/li>\n\n\n\n<li><code>next-connect<\/code>. This will help us add Multer as a middleware to a route handler.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/image-and-video-upload-to-cloudinary-using-nextjs-server-side-multer-and-xata-database-3l9f#create-a-raw-createcardjs-endraw-file\"><\/a>Creating a&nbsp;<code>create-card.js<\/code>&nbsp;File<\/h2>\n\n\n\n<p>We&#8217;ll have to create a card to upload an image and a video. So, create a file called&nbsp;<code>create-card.js<\/code>&nbsp;in the&nbsp;<code>api<\/code>&nbsp;folder of the&nbsp;<code>pages<\/code>&nbsp;folder.<\/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> nc <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next-connect'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { getToken } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next-auth\/jwt'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> multer <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'multer'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> path <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'path'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> DatauriParser <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'datauri\/parser'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> cloudinary <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/..\/utils\/cloudinary'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { getXataClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/..\/utils\/xata'<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> xata = getXataClient();\n\n<span class=\"hljs-keyword\">const<\/span> handler = nc({\n  <span class=\"hljs-attr\">onError<\/span>: <span class=\"hljs-function\">(<span class=\"hljs-params\">res<\/span>) =&gt;<\/span> {\n    res.status(<span class=\"hljs-number\">500<\/span>).end(<span class=\"hljs-string\">'Something broke!'<\/span>);\n  },\n  <span class=\"hljs-attr\">onNoMatch<\/span>: <span class=\"hljs-function\">(<span class=\"hljs-params\">req, res<\/span>) =&gt;<\/span> {\n    res.status(<span class=\"hljs-number\">404<\/span>).end(<span class=\"hljs-string\">'Page is not found'<\/span>);\n  },\n})\n  <span class=\"hljs-comment\">\/\/ uploading two files<\/span>\n  .use(multer().any())\n  .post(<span class=\"hljs-keyword\">async<\/span> (req, res) =&gt; {\n    <span class=\"hljs-comment\">\/\/ get user's token<\/span>\n    <span class=\"hljs-keyword\">const<\/span> token = <span class=\"hljs-keyword\">await<\/span> getToken({ req });\n\n    <span class=\"hljs-comment\">\/\/ if no token<\/span>\n    <span class=\"hljs-keyword\">if<\/span> (!token) {\n      <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">401<\/span>).json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">'You are not signed in'<\/span>, <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-literal\">null<\/span> });\n    }\n    <span class=\"hljs-comment\">\/\/ get parsed image and video from multer<\/span>\n    <span class=\"hljs-keyword\">const<\/span> image = req.files.filter(<span class=\"hljs-function\">(<span class=\"hljs-params\">file<\/span>) =&gt;<\/span> file.fieldname === <span class=\"hljs-string\">'image'<\/span>)&#91;<span class=\"hljs-number\">0<\/span>];\n    <span class=\"hljs-keyword\">const<\/span> video = req.files.filter(<span class=\"hljs-function\">(<span class=\"hljs-params\">file<\/span>) =&gt;<\/span> file.fieldname === <span class=\"hljs-string\">'video'<\/span>)&#91;<span class=\"hljs-number\">0<\/span>];\n    <span class=\"hljs-comment\">\/\/ create a neew Data URI parser<\/span>\n    <span class=\"hljs-keyword\">const<\/span> parser = <span class=\"hljs-keyword\">new<\/span> DatauriParser();\n    <span class=\"hljs-keyword\">try<\/span> {\n      <span class=\"hljs-comment\">\/\/ create image<\/span>\n      <span class=\"hljs-keyword\">const<\/span> createImage = <span class=\"hljs-keyword\">async<\/span> (img) =&gt; {\n        <span class=\"hljs-keyword\">const<\/span> base64Image = parser.format(path.extname(img.originalname).toString(), img.buffer);\n        <span class=\"hljs-keyword\">const<\/span> uploadedImageResponse = <span class=\"hljs-keyword\">await<\/span> cloudinary.uploader.upload(base64Image.content, <span class=\"hljs-string\">'flashcards'<\/span>, { <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">'image'<\/span> });\n        <span class=\"hljs-keyword\">return<\/span> uploadedImageResponse;\n      };\n\n      <span class=\"hljs-comment\">\/\/ create video<\/span>\n      <span class=\"hljs-keyword\">const<\/span> createVideo = <span class=\"hljs-keyword\">async<\/span> (vid) =&gt; {\n        <span class=\"hljs-keyword\">const<\/span> base64Video = parser.format(path.extname(vid.originalname).toString(), vid.buffer);\n        <span class=\"hljs-keyword\">const<\/span> uploadedVideoResponse = <span class=\"hljs-keyword\">await<\/span> cloudinary.uploader.upload(base64Video.content, <span class=\"hljs-string\">'flashcards'<\/span>, { <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">'video'<\/span> });\n        <span class=\"hljs-keyword\">return<\/span> uploadedVideoResponse;\n      };\n\n      <span class=\"hljs-comment\">\/\/ saving information<\/span>\n      <span class=\"hljs-keyword\">const<\/span> createdImage = <span class=\"hljs-keyword\">await<\/span> createImage(image);\n      <span class=\"hljs-keyword\">const<\/span> imageUrl = createdImage.url;\n      <span class=\"hljs-keyword\">const<\/span> image_id = createdImage.public_id;\n      <span class=\"hljs-keyword\">const<\/span> image_signature = createdImage.signature;\n      <span class=\"hljs-keyword\">const<\/span> createdVideo = video ? <span class=\"hljs-keyword\">await<\/span> createVideo(video) : <span class=\"hljs-literal\">null<\/span>;\n      <span class=\"hljs-keyword\">const<\/span> videoUrl = createdVideo?.url;\n      <span class=\"hljs-keyword\">const<\/span> video_id = createdVideo?.public_id;\n      <span class=\"hljs-keyword\">const<\/span> video_signature = createVideo?.signature;\n\n      <span class=\"hljs-comment\">\/\/ creating a new card<\/span>\n      <span class=\"hljs-keyword\">const<\/span> card = <span class=\"hljs-keyword\">await<\/span> xata.db.Cards.create({\n        <span class=\"hljs-attr\">name<\/span>: req.body.cardName,\n        <span class=\"hljs-attr\">category<\/span>: req.body.category,\n        <span class=\"hljs-attr\">color<\/span>: req.body.cardColor,\n        <span class=\"hljs-attr\">front<\/span>: req.body.front,\n        <span class=\"hljs-attr\">back<\/span>: req.body.back,\n        <span class=\"hljs-attr\">image<\/span>: imageUrl,\n        image_id,\n        image_signature,\n        <span class=\"hljs-attr\">video<\/span>: videoUrl,\n        video_id,\n        video_signature,\n        <span class=\"hljs-attr\">user<\/span>: token.user.id,\n      });\n      res.json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-literal\">null<\/span>, <span class=\"hljs-attr\">data<\/span>: card });\n    } <span class=\"hljs-keyword\">catch<\/span> (error) {\n      res.status(<span class=\"hljs-number\">500<\/span>).json({ error, <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-literal\">null<\/span> });\n    }\n  });\n\n<span class=\"hljs-comment\">\/\/ disable body parser<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> config = {\n  <span class=\"hljs-attr\">api<\/span>: {\n    <span class=\"hljs-attr\">bodyParser<\/span>: <span class=\"hljs-literal\">false<\/span>,\n  },\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> handler;\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>This will handle any POST request to&nbsp;<code>\/api\/create-card<\/code>. So, the frontend will send form data, including the image and video we want to upload.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Line 1<\/strong>. We&#8217;ll import the package&nbsp;<code>next-connnect<\/code>&nbsp;.<\/li>\n\n\n\n<li><strong>Line 9<\/strong>: We&#8217;ll create a new Xata instance.<\/li>\n\n\n\n<li><strong>Line 20<\/strong>: We&#8217;ll apply the Multer middleware. The&nbsp;<strong>Multer<\/strong>&nbsp;middleware ensures that it parses any files using the&nbsp;<code>any()<\/code>&nbsp;method. And we store the image and video for each card inside the variables&nbsp;<code>image<\/code>&nbsp;and&nbsp;<code>video<\/code>&nbsp;in&nbsp;<strong>lines 30<\/strong>&nbsp;and&nbsp;<strong>31.<\/strong><\/li>\n\n\n\n<li><strong>Line 33<\/strong>: We&#8217;ll create the&nbsp;<code>datauri\/parser<\/code>&nbsp;instance to convert the parsed files to a base 64 encodings file. This way, we can upload the image and video generated in&nbsp;<strong>lines 40<\/strong>&nbsp;and&nbsp;<strong>47<\/strong>&nbsp;to cloudinary.<\/li>\n\n\n\n<li><strong>Line 36-40<\/strong>: Here, we&#8217;ll convert the parsed image file to a base 64 encoding for upload to Cloudinary. This is done using the&nbsp;<code>uploader.upload()<\/code>&nbsp;method of the Cloudinary SDK. Notice we passed in the upload presets,&nbsp;<code>flashcards,<\/code>&nbsp;and an option&nbsp;<code>{ resource_type: 'image' }<\/code>&nbsp;telling Cloudinary that this is an image we want to upload. This method returns a response, including the URL of the new Image created, which is stored in the database as&nbsp;<code>image<\/code>.<\/li>\n\n\n\n<li><strong>Line 43-47<\/strong>: Same as&nbsp;<strong>Line 36-40<\/strong>. The only difference is this time, we tell Cloudinary that it is a video&nbsp;<code>{ resource_type: 'video' }<\/code>.<\/li>\n\n\n\n<li><strong>Line 60-73<\/strong>: We&#8217;ll create a new card by invoking the&nbsp;<code>create()<\/code>&nbsp;function of Xata and passing the values from the frontend.<\/li>\n<\/ul>\n\n\n\n<p>See what will be sent from the frontend in&nbsp;<strong>line<\/strong><strong>s<\/strong>&nbsp;<strong>115-126<\/strong>&nbsp;below.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" 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> { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { useSession } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next-auth\/react'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { useRouter } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next\/router'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { toast } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react-toastify'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> LoginToContinue <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/components\/LoginToContinue'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> SkeletonLoader <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/components\/SkeletonLoader'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'react-quill\/dist\/quill.snow.css'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'react-quill\/dist\/quill.bubble.css'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { modules, formats } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/utils\/editor'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { isImage, isVideo, validateSize } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/utils\/fileValidation'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> ProcessIndicator <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/components\/ProcessIndicator'<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> ReactQuill = <span class=\"hljs-keyword\">typeof<\/span> <span class=\"hljs-built_in\">window<\/span> === <span class=\"hljs-string\">'object'<\/span> ? <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'react-quill'<\/span>) : <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> <span class=\"hljs-literal\">false<\/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\">Create<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> router = useRouter();\n  <span class=\"hljs-keyword\">const<\/span> colors = &#91;<span class=\"hljs-string\">'#FFFFFF'<\/span>, <span class=\"hljs-string\">'#000000'<\/span>, <span class=\"hljs-string\">'#251447'<\/span>, <span class=\"hljs-string\">'#870A30'<\/span>];\n  <span class=\"hljs-keyword\">const<\/span> { <span class=\"hljs-attr\">data<\/span>: session, status } = useSession();\n  <span class=\"hljs-keyword\">const<\/span> &#91;imageSrc, setImageSrc] = useState(<span class=\"hljs-string\">''<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;videoSrc, setVideoSrc] = useState(<span class=\"hljs-string\">''<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;image, setImage] = useState();\n  <span class=\"hljs-keyword\">const<\/span> &#91;video, setVideo] = useState();\n  <span class=\"hljs-keyword\">const<\/span> &#91;front, setFront] = useState(<span class=\"hljs-string\">''<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;back, setBack] = useState(<span class=\"hljs-string\">''<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;imageError, setImageError] = useState(<span class=\"hljs-string\">''<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;videoError, setVideoError] = useState(<span class=\"hljs-string\">''<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;cardName, setCardName] = useState(<span class=\"hljs-string\">''<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;category, setCategory] = useState(<span class=\"hljs-string\">''<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;cardColor, setCardColor] = useState(<span class=\"hljs-string\">'#FFFFFF'<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;loading, setLoading] = useState(<span class=\"hljs-literal\">false<\/span>);\n\n  <span class=\"hljs-keyword\">if<\/span> (status === <span class=\"hljs-string\">'loading'<\/span>) {\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SkeletonLoader<\/span> \/&gt;<\/span><\/span>;\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> handleCardName = <span class=\"hljs-function\">(<span class=\"hljs-params\">e<\/span>) =&gt;<\/span> {\n    setCardName(e.target.value);\n  };\n  <span class=\"hljs-keyword\">const<\/span> handleImageChange = <span class=\"hljs-function\">(<span class=\"hljs-params\">e<\/span>) =&gt;<\/span> {\n    setImageError(<span class=\"hljs-string\">''<\/span>);\n    <span class=\"hljs-keyword\">const<\/span> img = e.target.files&#91;<span class=\"hljs-number\">0<\/span>];\n    <span class=\"hljs-comment\">\/\/ if no image selected<\/span>\n    <span class=\"hljs-keyword\">if<\/span> (!img) {\n      <span class=\"hljs-keyword\">return<\/span>;\n    }\n\n    <span class=\"hljs-comment\">\/\/ check if image<\/span>\n    <span class=\"hljs-keyword\">const<\/span> result = isImage(img.name);\n    <span class=\"hljs-keyword\">if<\/span> (!result) {\n      <span class=\"hljs-keyword\">const<\/span> error = <span class=\"hljs-string\">'File type should be a image'<\/span>;\n      toast(error, { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'error'<\/span> });\n      setImageError(error);\n      <span class=\"hljs-keyword\">return<\/span>;\n    }\n    <span class=\"hljs-keyword\">const<\/span> isImageLarge = validateSize(img);\n    <span class=\"hljs-keyword\">if<\/span> (isImageLarge) {\n      <span class=\"hljs-keyword\">const<\/span> error = <span class=\"hljs-string\">'File must be less or equal to 5MB'<\/span>;\n      toast(error, { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'error'<\/span> });\n      setImageError(error);\n      <span class=\"hljs-keyword\">return<\/span>;\n    }\n    <span class=\"hljs-keyword\">const<\/span> reader = <span class=\"hljs-keyword\">new<\/span> FileReader();\n    <span class=\"hljs-comment\">\/\/ converts to BASE 64<\/span>\n    reader.readAsDataURL(img);\n    reader.addEventListener(<span class=\"hljs-string\">'load'<\/span>, () =&gt; {\n      setImageSrc(reader.result);\n      setImage(img);\n    });\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> handleVideoChange = <span class=\"hljs-function\">(<span class=\"hljs-params\">e<\/span>) =&gt;<\/span> {\n    setVideoError(<span class=\"hljs-string\">''<\/span>);\n    <span class=\"hljs-keyword\">const<\/span> vid = e.target.files&#91;<span class=\"hljs-number\">0<\/span>];\n    <span class=\"hljs-comment\">\/\/ if no video selected<\/span>\n    <span class=\"hljs-keyword\">if<\/span> (!vid) {\n      <span class=\"hljs-keyword\">return<\/span>;\n    }\n\n    <span class=\"hljs-comment\">\/\/ check if video<\/span>\n    <span class=\"hljs-keyword\">const<\/span> result = isVideo(vid.name);\n    <span class=\"hljs-keyword\">if<\/span> (!result) {\n      <span class=\"hljs-keyword\">const<\/span> error = <span class=\"hljs-string\">'File type should be a video'<\/span>;\n      toast(error, { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'error'<\/span> });\n      setVideoError(error);\n      <span class=\"hljs-keyword\">return<\/span>;\n    }\n    <span class=\"hljs-keyword\">const<\/span> isFileLarge = validateSize(vid);\n    <span class=\"hljs-keyword\">if<\/span> (isFileLarge) {\n      <span class=\"hljs-keyword\">const<\/span> error = <span class=\"hljs-string\">'Video file must be less or equal to 5MB'<\/span>;\n      toast(error, { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'error'<\/span> });\n      setVideoError((error));\n      <span class=\"hljs-keyword\">return<\/span>;\n    }\n    <span class=\"hljs-keyword\">const<\/span> blobURL = URL.createObjectURL(vid);\n    <span class=\"hljs-keyword\">const<\/span> reader = <span class=\"hljs-keyword\">new<\/span> FileReader();\n    <span class=\"hljs-comment\">\/\/ converts to BASE 64<\/span>\n    reader.readAsDataURL(vid);\n    reader.addEventListener(<span class=\"hljs-string\">'load'<\/span>, () =&gt; {\n      setVideo(<span class=\"hljs-string\">''<\/span>);\n      setVideoSrc(reader.result);\n      setVideo(vid);\n    });\n  };\n\n  <span class=\"hljs-keyword\">if<\/span> (status === <span class=\"hljs-string\">'unauthenticated'<\/span>) {\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">LoginToContinue<\/span> \/&gt;<\/span><\/span>;\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> handleSubmit = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n    <span class=\"hljs-keyword\">if<\/span> (!cardName || !front || !back || !image || !category) {\n      toast(<span class=\"hljs-string\">'Please enter required fields with asterisk'<\/span>, { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'error'<\/span> });\n      <span class=\"hljs-keyword\">return<\/span>;\n    }\n    setLoading(<span class=\"hljs-literal\">true<\/span>);\n    <span class=\"hljs-keyword\">const<\/span> formData = <span class=\"hljs-keyword\">new<\/span> FormData();\n    formData.append(<span class=\"hljs-string\">'cardName'<\/span>, cardName);\n    formData.append(<span class=\"hljs-string\">'cardColor'<\/span>, cardColor);\n    formData.append(<span class=\"hljs-string\">'front'<\/span>, front);\n    formData.append(<span class=\"hljs-string\">'back'<\/span>, back);\n    formData.append(<span class=\"hljs-string\">'image'<\/span>, image);\n    formData.append(<span class=\"hljs-string\">'video'<\/span>, video);\n    formData.append(<span class=\"hljs-string\">'category'<\/span>, category);\n    <span class=\"hljs-keyword\">const<\/span> res = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">'\/api\/create-card'<\/span>, {\n      <span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">'POST'<\/span>,\n      <span class=\"hljs-attr\">body<\/span>: formData,\n    });\n    <span class=\"hljs-keyword\">const<\/span> { error } = <span class=\"hljs-keyword\">await<\/span> res.json();\n    <span class=\"hljs-keyword\">if<\/span> (error) {\n      toast(<span class=\"hljs-string\">'There was error'<\/span>, { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'error'<\/span> });\n      setLoading(<span class=\"hljs-literal\">false<\/span>);\n      <span class=\"hljs-keyword\">return<\/span>;\n    }\n    toast(<span class=\"hljs-string\">'Card created successfully!!!'<\/span>, { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-string\">'success'<\/span> });\n    setLoading(<span class=\"hljs-literal\">false<\/span>);\n    router.push(<span class=\"hljs-string\">'\/my-cards'<\/span>);\n  };\n\n  <span class=\"hljs-keyword\">return<\/span> (\n\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\" p-5 dark:bg-black w-full dark:text-white\"<\/span>&gt;<\/span>\n      {loading ? <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ProcessIndicator<\/span> \/&gt;<\/span>\n        : (\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"my-5\"<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"font-bold\"<\/span>&gt;<\/span>\n                Name of Card\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-red-400\"<\/span>&gt;<\/span>*<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleCardName}<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{cardName}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full text-black border p-2 my-5 dark:placeholder:text-gray-600\"<\/span> <span class=\"hljs-attr\">placeholder<\/span>=<span class=\"hljs-string\">\"Xata Multiple-Select\"<\/span> \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"my-5\"<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"font-bold\"<\/span>&gt;<\/span>\n                Card Category\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-red-400\"<\/span>&gt;<\/span>*<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">select<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"category\"<\/span> <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{(e)<\/span> =&gt;<\/span> { setCategory(e.target.value); }} className=\"block my-5\"&gt;\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"\"<\/span>&gt;<\/span>__Select__<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"programming\"<\/span>&gt;<\/span>Programming<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"science\"<\/span>&gt;<\/span>Science<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"art\"<\/span>&gt;<\/span>Art<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"technology\"<\/span>&gt;<\/span>Technology<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"technical-writing\"<\/span>&gt;<\/span>Technical Writing<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"education\"<\/span>&gt;<\/span>Education<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">select<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            {\/* SELECT CARD COLOR *\/}\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"my-5 dark:text-white font-bold\"<\/span>&gt;<\/span>\n                Select Card Color\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-red-400\"<\/span>&gt;<\/span>*<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex space-x-10 py-5 overflow-x-scroll items-center max-w-5xl justify-between md:justify-start md:space-x-10  dark:text-gray-400\"<\/span>&gt;<\/span>\n                {colors.map((color, index) =&gt; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> { setCardColor(color); }} key={color} style={{ background: color }} className={`p-10 rounded-md dark:border shadow-xl ${color === cardColor ? 'border-4 border-blue-700' : ''}`} \/&gt;)}\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            {\/* CHOOSE VIDEO OR PICTURE *\/}\n\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"my-5\"<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"\"<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n                  Select Picture\n                  {' '}\n                  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-red-500\"<\/span>&gt;<\/span>(Max 5MB)<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n                  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-red-400\"<\/span>&gt;<\/span>*<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"my-5 text-red-400\"<\/span>&gt;<\/span>{imageError}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"file\"<\/span> <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleImageChange}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block\"<\/span> \/&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n              {image &amp;&amp; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">\"card\"<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{imageSrc}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"basis-1\/2 h-auto w-48 my-5\"<\/span> <span class=\"hljs-attr\">accept<\/span>=<span class=\"hljs-string\">\"image\/*\"<\/span> \/&gt;<\/span>}\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"my-5\"<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n                Select Video\n                {' '}\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-red-500\"<\/span>&gt;<\/span>(Max 5MB)<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"my-5 text-red-400\"<\/span>&gt;<\/span>{videoError}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"file\"<\/span> <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleVideoChange}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block my-5\"<\/span> <span class=\"hljs-attr\">accept<\/span>=<span class=\"hljs-string\">\"video\/mp4,video\/x-m4v,video\/*\"<\/span> \/&gt;<\/span>\n              {video &amp;&amp; (\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{videoSrc}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-48 h-auto\"<\/span> <span class=\"hljs-attr\">controls<\/span> \/&gt;<\/span>\n              )}\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n            {\/* ENTER CONTENT *\/}\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full my-5 dark:text-white\"<\/span>&gt;<\/span>\n              {\/* FRONT *\/}\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"my-5\"<\/span>&gt;<\/span>\n                FRONT\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-red-400\"<\/span>&gt;<\/span>*<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ReactQuill<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"editor\"<\/span> <span class=\"hljs-attr\">formats<\/span>=<span class=\"hljs-string\">{formats}<\/span> <span class=\"hljs-attr\">modules<\/span>=<span class=\"hljs-string\">{modules}<\/span> <span class=\"hljs-attr\">theme<\/span>=<span class=\"hljs-string\">\"snow\"<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{front}<\/span> <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{setFront}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full h-96 pb-10  dark:text-white\"<\/span> \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full my-10 dark:text-white\"<\/span>&gt;<\/span>\n              {\/* BACK *\/}\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"my-5\"<\/span>&gt;<\/span>\n                BACK\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-red-400\"<\/span>&gt;<\/span>*<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ReactQuill<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"editor\"<\/span> <span class=\"hljs-attr\">formats<\/span>=<span class=\"hljs-string\">{formats}<\/span> <span class=\"hljs-attr\">modules<\/span>=<span class=\"hljs-string\">{modules}<\/span> <span class=\"hljs-attr\">theme<\/span>=<span class=\"hljs-string\">\"snow\"<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{back}<\/span> <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{setBack}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full h-96 pb-10 dark:text-white\"<\/span> \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"button\"<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{handleSubmit}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"p-2 bg-black text-white my-5 rounded-md\"<\/span>&gt;<\/span>\n              Create Flashcard\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        )}\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\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\">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<h2 class=\"wp-block-heading\"><strong>Updating an Existing Image<\/strong><\/h2>\n\n\n\n<p>Updating an existing image in Cloudinary also means updating our card. Create a new API route handler called&nbsp;<code>update-card-image.js<\/code>.<\/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> nc <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next-connect'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { getToken } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next-auth\/jwt'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> multer <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'multer'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> path <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'path'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> DatauriParser <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'datauri\/parser'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> cloudinary <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/..\/utils\/cloudinary'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { getXataClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/..\/utils\/xata'<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> handler = nc({\n  <span class=\"hljs-attr\">onError<\/span>: <span class=\"hljs-function\">(<span class=\"hljs-params\">err, res<\/span>) =&gt;<\/span> {\n    res.status(<span class=\"hljs-number\">500<\/span>).end(<span class=\"hljs-string\">'Something broke!'<\/span>);\n  },\n  <span class=\"hljs-attr\">onNoMatch<\/span>: <span class=\"hljs-function\">(<span class=\"hljs-params\">req, res<\/span>) =&gt;<\/span> {\n    res.status(<span class=\"hljs-number\">404<\/span>).end(<span class=\"hljs-string\">'Page is not found'<\/span>);\n  },\n})\n  .use(multer().single(<span class=\"hljs-string\">'image'<\/span>))\n  .post(<span class=\"hljs-keyword\">async<\/span> (req, res) =&gt; {\n    <span class=\"hljs-keyword\">const<\/span> xata = getXataClient();\n    <span class=\"hljs-keyword\">const<\/span> image = req.file;\n\n    <span class=\"hljs-keyword\">const<\/span> token = <span class=\"hljs-keyword\">await<\/span> getToken({ req });\n    <span class=\"hljs-comment\">\/\/ if no token<\/span>\n    <span class=\"hljs-keyword\">if<\/span> (!token) {\n      <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">403<\/span>).json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">'You are not signed in'<\/span>, <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-literal\">null<\/span> });\n    }\n\n    <span class=\"hljs-keyword\">const<\/span> userId = token.user.id;\n    <span class=\"hljs-comment\">\/\/ check if card is user's<\/span>\n    <span class=\"hljs-keyword\">if<\/span> (!(req.body.userId === userId)) {\n      <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">403<\/span>).json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">'You cannot update this card.'<\/span>, <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-literal\">null<\/span> });\n    }\n\n    <span class=\"hljs-keyword\">const<\/span> parser = <span class=\"hljs-keyword\">new<\/span> DatauriParser();\n    <span class=\"hljs-keyword\">try<\/span> {\n      <span class=\"hljs-comment\">\/\/ destroy existing image on cloudinary<\/span>\n      <span class=\"hljs-keyword\">await<\/span> cloudinary.v2.uploader.destroy(req.body.imageId);\n      <span class=\"hljs-comment\">\/\/ create new one<\/span>\n      <span class=\"hljs-keyword\">const<\/span> base64Image = <span class=\"hljs-keyword\">await<\/span> parser.format(path.extname(image.originalname).toString(), image.buffer);\n      <span class=\"hljs-keyword\">const<\/span> uploadedImageResponse = <span class=\"hljs-keyword\">await<\/span> cloudinary.uploader.upload(base64Image.content, <span class=\"hljs-string\">'flashcards'<\/span>, { <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">'image'<\/span> });\n      <span class=\"hljs-keyword\">const<\/span> image_id = uploadedImageResponse.public_id;\n      <span class=\"hljs-keyword\">const<\/span> image_signature = uploadedImageResponse.signature;\n      <span class=\"hljs-keyword\">const<\/span> card = <span class=\"hljs-keyword\">await<\/span> xata.db.Cards.update(req.body.cardId, {\n        <span class=\"hljs-attr\">image<\/span>: <span class=\"hljs-keyword\">await<\/span> uploadedImageResponse.url,\n        image_id,\n        image_signature,\n      });\n\n      res.json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-literal\">null<\/span>, <span class=\"hljs-attr\">data<\/span>: card });\n    } <span class=\"hljs-keyword\">catch<\/span> (error) {\n      res.status(<span class=\"hljs-number\">500<\/span>).json({ error, <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-literal\">null<\/span> });\n    }\n  });\n\n<span class=\"hljs-comment\">\/\/ disable body parser<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> config = {\n  <span class=\"hljs-attr\">api<\/span>: {\n    <span class=\"hljs-attr\">bodyParser<\/span>: <span class=\"hljs-literal\">false<\/span>,\n  },\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> handler;\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>There isn&#8217;t much difference from&nbsp;<code>create-card.js<\/code>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Line 17:<\/strong>&nbsp;We told Multer that it should parse a single file named&nbsp;<code>image<\/code>. This is the name of the form data image from the frontend.<\/li>\n\n\n\n<li><strong>Line 37<\/strong>: We&#8217;ll delete the existing <a href=\"https:\/\/cloudinary.com\/products\/image\">Cloudinary image<\/a> of a card by invoking the Cloudinary\u00a0<code>destroy()<\/code>\u00a0method. This method only requires the id of the image to delete.<\/li>\n\n\n\n<li><strong>Line 43<\/strong>: We&#8217;ll update the card with the new image URL, id, and signature.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Updating an Existing Video<\/strong><\/h2>\n\n\n\n<p>This is the same as the code above. We&#8217;ll create a new file called&nbsp;<code>update-card-video<\/code>&nbsp;. The only difference is that this time we&#8217;ll tell Multer to parse a file named \u201cvideo\u201d in&nbsp;<strong>line 17<\/strong>. See the code below:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" 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> nc <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next-connect'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { getToken } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next-auth\/jwt'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> multer <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'multer'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> path <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'path'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> DatauriParser <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'datauri\/parser'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> cloudinary <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/..\/utils\/cloudinary'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { getXataClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/..\/utils\/xata'<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> handler = nc({\n  <span class=\"hljs-attr\">onError<\/span>: <span class=\"hljs-function\">(<span class=\"hljs-params\">err, res<\/span>) =&gt;<\/span> {\n    res.status(<span class=\"hljs-number\">500<\/span>).end(<span class=\"hljs-string\">'Something broke!'<\/span>);\n  },\n  <span class=\"hljs-attr\">onNoMatch<\/span>: <span class=\"hljs-function\">(<span class=\"hljs-params\">req, res<\/span>) =&gt;<\/span> {\n    res.status(<span class=\"hljs-number\">404<\/span>).end(<span class=\"hljs-string\">'Page is not found'<\/span>);\n  },\n})\n  .use(multer().single(<span class=\"hljs-string\">'video'<\/span>))\n  .post(<span class=\"hljs-keyword\">async<\/span> (req, res) =&gt; {\n    <span class=\"hljs-keyword\">const<\/span> xata = getXataClient();\n    <span class=\"hljs-keyword\">const<\/span> video = req.file;\n\n    <span class=\"hljs-keyword\">const<\/span> parser = <span class=\"hljs-keyword\">new<\/span> DatauriParser();\n    <span class=\"hljs-keyword\">try<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> token = <span class=\"hljs-keyword\">await<\/span> getToken({ req });\n      <span class=\"hljs-comment\">\/\/ if no token<\/span>\n      <span class=\"hljs-keyword\">if<\/span> (!token) {\n        <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">403<\/span>).json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">'You are not signed in'<\/span>, <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-literal\">null<\/span> });\n      }\n      <span class=\"hljs-keyword\">const<\/span> userId = token.user.id;\n      <span class=\"hljs-comment\">\/\/ check if card is user's<\/span>\n      <span class=\"hljs-keyword\">if<\/span> (!(req.body.userId === userId)) {\n        <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">403<\/span>).json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">'You cannot update this card.'<\/span>, <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-literal\">null<\/span> });\n      }\n\n      <span class=\"hljs-comment\">\/\/ destroy any existing video on cloudinary<\/span>\n      <span class=\"hljs-keyword\">if<\/span> (req.body.videoId !== <span class=\"hljs-string\">'null'<\/span>) {\n        <span class=\"hljs-keyword\">await<\/span> cloudinary.v2.uploader.destroy(req.body.videoId);\n      }\n\n      <span class=\"hljs-comment\">\/\/ create new one<\/span>\n      <span class=\"hljs-keyword\">const<\/span> base64Video = <span class=\"hljs-keyword\">await<\/span> parser.format(path.extname(video.originalname).toString(), video.buffer);\n      <span class=\"hljs-keyword\">const<\/span> uploadedVideoResponse = <span class=\"hljs-keyword\">await<\/span> cloudinary.uploader.upload(base64Video.content, <span class=\"hljs-string\">'flashcards'<\/span>, { <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">'video'<\/span> });\n      <span class=\"hljs-keyword\">const<\/span> video_id = uploadedVideoResponse.public_id;\n      <span class=\"hljs-keyword\">const<\/span> video_signature = uploadedVideoResponse.signature;\n      <span class=\"hljs-keyword\">const<\/span> card = <span class=\"hljs-keyword\">await<\/span> xata.db.Cards.update(req.body.cardId, {\n        <span class=\"hljs-attr\">video<\/span>: <span class=\"hljs-keyword\">await<\/span> uploadedVideoResponse.url,\n        video_id,\n        video_signature,\n      });\n      res.json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-literal\">null<\/span>, <span class=\"hljs-attr\">data<\/span>: card });\n    } <span class=\"hljs-keyword\">catch<\/span> (error) {\n      res.status(<span class=\"hljs-number\">500<\/span>).json({ error, <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-literal\">null<\/span> });\n    }\n  });\n\n<span class=\"hljs-comment\">\/\/ disable body parser<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> config = {\n  <span class=\"hljs-attr\">api<\/span>: {\n    <span class=\"hljs-attr\">bodyParser<\/span>: <span class=\"hljs-literal\">false<\/span>,\n  },\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> handler;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><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<h2 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/image-and-video-upload-to-cloudinary-using-nextjs-server-side-multer-and-xata-database-3l9f#deleting-images-and-videos\"><\/a>Deleting Images and Videos<\/h2>\n\n\n\n<p>In deleting a card, we&#8217;ll delete the image and video.<\/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> { getToken } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next-auth\/jwt'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { getXataClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/..\/utils\/xata'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> cloudinary <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/..\/utils\/cloudinary'<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> handler = <span class=\"hljs-keyword\">async<\/span> (req, res) =&gt; {\n  <span class=\"hljs-keyword\">try<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> xata = getXataClient();\n    <span class=\"hljs-keyword\">const<\/span> token = <span class=\"hljs-keyword\">await<\/span> getToken({ req });\n    <span class=\"hljs-keyword\">if<\/span> (!token) {\n      <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">403<\/span>).json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">'Please signin to perform this operation.'<\/span>, <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-literal\">null<\/span> });\n    }\n\n    <span class=\"hljs-keyword\">const<\/span> userId = token.user.id;\n    <span class=\"hljs-comment\">\/\/ check if owner<\/span>\n    <span class=\"hljs-keyword\">if<\/span> (!(req.body.user.id === userId)) {\n      <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">403<\/span>).json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">'Please you cannot delete this card'<\/span>, <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-literal\">null<\/span> });\n    }\n\n    <span class=\"hljs-comment\">\/\/ delete video if any<\/span>\n    <span class=\"hljs-keyword\">if<\/span> (req.body.video_id) {\n      <span class=\"hljs-keyword\">await<\/span> cloudinary.v2.uploader.destroy(req.body.video_id);\n    }\n\n    <span class=\"hljs-comment\">\/\/ delete image if any<\/span>\n    <span class=\"hljs-keyword\">if<\/span> (req.body.image_id) {\n      <span class=\"hljs-keyword\">await<\/span> cloudinary.v2.uploader.destroy(req.body.image_id);\n    }\n\n    <span class=\"hljs-comment\">\/\/ finally, delete card<\/span>\n    <span class=\"hljs-keyword\">const<\/span> record = <span class=\"hljs-keyword\">await<\/span> xata.db.Cards.delete(req.body.id);\n    <span class=\"hljs-keyword\">return<\/span> res.json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-literal\">null<\/span>, <span class=\"hljs-attr\">data<\/span>: record });\n  } <span class=\"hljs-keyword\">catch<\/span> (error) {\n    res.status(<span class=\"hljs-number\">500<\/span>).json({ <span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-string\">'something went wrong'<\/span>, <span class=\"hljs-attr\">data<\/span>: <span class=\"hljs-literal\">null<\/span> });\n  }\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> handler;\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<ul class=\"wp-block-list\">\n<li><strong>Line 21 and 26<\/strong>: We&#8217;ll call the Cloudinary&nbsp;<code>destroy()<\/code>&nbsp;methods and passed the image id and video id of the card we want to delete.<\/li>\n\n\n\n<li><strong>Line 30<\/strong>: We&#8217;ll invoke the&nbsp;<code>delete()<\/code>&nbsp;method of Xata by passing the id of the card we want to delete.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/image-and-video-upload-to-cloudinary-using-nextjs-server-side-multer-and-xata-database-3l9f#live-demo\"><\/a>Live Demo<\/h2>\n\n\n\n<figure class=\"wp-block-embed\"><div class=\"wp-block-embed__wrapper\">\nhttps:\/\/hackmamba-xata-cloudinary-project.vercel.app\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/image-and-video-upload-to-cloudinary-using-nextjs-server-side-multer-and-xata-database-3l9f#conclusion\"><\/a>Conclusion<\/h2>\n\n\n\n<p>In this blog post, we looked at uploading images and videos to Cloudinary using Next.js-server side and persisting data in the database using Xata. The frontend and full code have been provided in the GitHub URL section of this post. Visit here for the&nbsp;<a href=\"https:\/\/hackmamba-xata-cloudinary-project.vercel.app\/\" target=\"_blank\" rel=\"noreferrer noopener\">live application<\/a> and <a href=\"https:\/\/cloudinary.com\/users\/register_free\">sign up for a free Cloudinary account<\/a> today.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It may not be surprising that you&#8217;ve already uploaded a file today, whether it will disappear after a time or be stored in an online database. So, it&#8217;s become imperative to create applications enabling file uploads. Using Next.js server-side, you can implement this. In this blog post, we&#8217;ll discuss the frontend, what our project does, [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":31475,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[212],"class_list":["post-31473","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-next-js"],"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>Uploading Images and Videos to Cloudinary Using Next.js Server-Side, Multer, and Xata Database<\/title>\n<meta name=\"description\" content=\"Use Next.js server-side to create applications that enable file uploads. This post discuss the frontend, what our project does, and the tools we need.\" \/>\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\/uploading-images-videos-next-js-server-side-multer-xata\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Uploading Images and Videos to Cloudinary Using Next.js Server-Side, Multer, and Xata Database\" \/>\n<meta property=\"og:description\" content=\"Use Next.js server-side to create applications that enable file uploads. This post discuss the frontend, what our project does, and the tools we need.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2023-10-16T14:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-04-16T20:19:29+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1696620194\/Blog-Hackmamba_Video_Images_Upload\/Blog-Hackmamba_Video_Images_Upload-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\/uploading-images-videos-next-js-server-side-multer-xata#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Uploading Images and Videos to Cloudinary Using Next.js Server-Side, Multer, and Xata Database\",\"datePublished\":\"2023-10-16T14:00:00+00:00\",\"dateModified\":\"2025-04-16T20:19:29+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata\"},\"wordCount\":1579,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1696620194\/Blog-Hackmamba_Video_Images_Upload\/Blog-Hackmamba_Video_Images_Upload.jpg?_i=AA\",\"keywords\":[\"Next.js\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2023\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata\",\"url\":\"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata\",\"name\":\"Uploading Images and Videos to Cloudinary Using Next.js Server-Side, Multer, and Xata Database\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1696620194\/Blog-Hackmamba_Video_Images_Upload\/Blog-Hackmamba_Video_Images_Upload.jpg?_i=AA\",\"datePublished\":\"2023-10-16T14:00:00+00:00\",\"dateModified\":\"2025-04-16T20:19:29+00:00\",\"description\":\"Use Next.js server-side to create applications that enable file uploads. This post discuss the frontend, what our project does, and the tools we need.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1696620194\/Blog-Hackmamba_Video_Images_Upload\/Blog-Hackmamba_Video_Images_Upload.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1696620194\/Blog-Hackmamba_Video_Images_Upload\/Blog-Hackmamba_Video_Images_Upload.jpg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Uploading Images and Videos to Cloudinary Using Next.js Server-Side, Multer, and Xata Database\"}]},{\"@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":"Uploading Images and Videos to Cloudinary Using Next.js Server-Side, Multer, and Xata Database","description":"Use Next.js server-side to create applications that enable file uploads. This post discuss the frontend, what our project does, and the tools we need.","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\/uploading-images-videos-next-js-server-side-multer-xata","og_locale":"en_US","og_type":"article","og_title":"Uploading Images and Videos to Cloudinary Using Next.js Server-Side, Multer, and Xata Database","og_description":"Use Next.js server-side to create applications that enable file uploads. This post discuss the frontend, what our project does, and the tools we need.","og_url":"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata","og_site_name":"Cloudinary Blog","article_published_time":"2023-10-16T14:00:00+00:00","article_modified_time":"2025-04-16T20:19:29+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1696620194\/Blog-Hackmamba_Video_Images_Upload\/Blog-Hackmamba_Video_Images_Upload-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\/uploading-images-videos-next-js-server-side-multer-xata#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Uploading Images and Videos to Cloudinary Using Next.js Server-Side, Multer, and Xata Database","datePublished":"2023-10-16T14:00:00+00:00","dateModified":"2025-04-16T20:19:29+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata"},"wordCount":1579,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1696620194\/Blog-Hackmamba_Video_Images_Upload\/Blog-Hackmamba_Video_Images_Upload.jpg?_i=AA","keywords":["Next.js"],"inLanguage":"en-US","copyrightYear":"2023","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata","url":"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata","name":"Uploading Images and Videos to Cloudinary Using Next.js Server-Side, Multer, and Xata Database","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1696620194\/Blog-Hackmamba_Video_Images_Upload\/Blog-Hackmamba_Video_Images_Upload.jpg?_i=AA","datePublished":"2023-10-16T14:00:00+00:00","dateModified":"2025-04-16T20:19:29+00:00","description":"Use Next.js server-side to create applications that enable file uploads. This post discuss the frontend, what our project does, and the tools we need.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1696620194\/Blog-Hackmamba_Video_Images_Upload\/Blog-Hackmamba_Video_Images_Upload.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1696620194\/Blog-Hackmamba_Video_Images_Upload\/Blog-Hackmamba_Video_Images_Upload.jpg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/uploading-images-videos-next-js-server-side-multer-xata#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Uploading Images and Videos to Cloudinary Using Next.js Server-Side, Multer, and Xata Database"}]},{"@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\/v1696620194\/Blog-Hackmamba_Video_Images_Upload\/Blog-Hackmamba_Video_Images_Upload.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/31473","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=31473"}],"version-history":[{"count":4,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/31473\/revisions"}],"predecessor-version":[{"id":37447,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/31473\/revisions\/37447"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/31475"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=31473"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=31473"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=31473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}