{"id":31766,"date":"2023-11-08T12:22:37","date_gmt":"2023-11-08T20:22:37","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=31766"},"modified":"2025-01-23T18:23:15","modified_gmt":"2025-01-24T02:23:15","slug":"building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata","title":{"rendered":"Building an E-commerce Storefront Using Next.js, Cloudinary, and Xata"},"content":{"rendered":"\n<p>As more and more people favor the convenience of online shopping, business owners turn to e-commerce platform builders, like Shopify, to sell more products. E-retail sales have surpassed 5.7 trillion dollars globally, and this number is only likely to rise in the upcoming years.<\/p>\n\n\n\n<p>In this blog post, you&#8217;ll earn how to integrate Xata and Cloudinary to Next.js to build an e-commerce storefront, the presentation layer of an online store that communicates with online customers. Next.js is a React framework used to create the user interface. Cloudinary is a robust media API used to manage media files, and Xata is a serverless database that stores users&#8217; data.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#prerequisite\"><\/a>Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Npm<\/li>\n\n\n\n<li>Node<\/li>\n\n\n\n<li>Git<\/li>\n\n\n\n<li>Basic knowledge of React.js and Next.js<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#getting-started\"><\/a>Getting Started<\/h2>\n\n\n\n<p>The source code for this application is publicly accessible on GitHub. You can clone it locally to your computer. This article will concentrate on how we will be utilizing Xata and Cloudinary in the project.<\/p>\n\n\n<div class='c-callout  c-callout--inline-title c-callout--note'><strong class='c-callout__title'>Note:<\/strong> <p>Cloudinary is a powerful media API for websites and mobile apps alike. Developers and marketers can effectively create, manage, and deploy their digital experiences using any browser, device, or bandwidth, thanks to Cloudinary. The architecture of Cloudinary was designed from the ground up to withstand enormous loads and manage essentially infinite amounts of assets and consumption.<\/p>\n<\/div>\n\n\n<p>After you clone it, you must add a Xata API key, Cloudinary cloud name, and the&nbsp;<strong>upload preset<\/strong>&nbsp;in an&nbsp;<code>.env<\/code>&nbsp;file at its root if you want to execute it locally.<\/p>\n\n\n<div class='c-callout  c-callout--inline-title c-callout--note'><strong class='c-callout__title'>Note:<\/strong> <p>Upload presets can be defined as a collection of activities that would occur upon uploading a resource. These activities could include applying an add-on capability, performing a transformation, or altering a resource\u2019s access control, among many other possibilities.<\/p>\n<\/div>\n\n\n<p>To clone the application, run the following command on the terminal:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">git <span class=\"hljs-keyword\">clone<\/span> https:<span class=\"hljs-comment\">\/\/github.com\/HarcourtHamsa\/Frontier.git<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Create a&nbsp;<code>.env<\/code>&nbsp;file in the root directory and paste your Xata API key:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">XATA_API_KEY=<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">your<\/span> <span class=\"hljs-attr\">Api<\/span> <span class=\"hljs-attr\">key<\/span>&gt;<\/span>\nCLOUD_NAME=<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">your<\/span> <span class=\"hljs-attr\">cloudinary<\/span> <span class=\"hljs-attr\">cloud<\/span> <span class=\"hljs-attr\">name<\/span>&gt;<\/span>\nUPLOAD_PRESET=<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">your<\/span> <span class=\"hljs-attr\">cloudinary<\/span> <span class=\"hljs-attr\">upload<\/span> <span class=\"hljs-attr\">preset<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><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>Start the project:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">npm run dev<\/code><\/span><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Adding Xata CLI<\/h2>\n\n\n\n<p>Xata is a serverless database with robust search and analytics. It&#8217;a comparable to a serverless relational database, a search engine, and an analytics engine, all hidden behind a uniform API.<\/p>\n\n\n\n<p>It&#8217;s advisable to use the SDK when adding Xata to the project. We can use the SDK in many JavaScript runtimes, including Node.js, Deno, Electron, etc.<\/p>\n\n\n\n<p>To install Xata, run the command:<\/p>\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\">i<\/span> <span class=\"hljs-selector-tag\">-g<\/span> <span class=\"hljs-keyword\">@xata<\/span>.io\/cli<\/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<p>Next, we have to authenticate Xata with the command:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">xata auth login<\/code><\/span><\/pre>\n\n\n<p>With the stated command, you can either paste in an existing API key or create a new one by opening a browser.<\/p>\n\n\n\n<p>Also, you will need to configure the application with the command below:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">xata init<\/code><\/span><\/pre>\n\n\n<p>The command above will start a brief survey that will assist us in setting up our project. Answer the questions, and use code generation.<\/p>\n\n\n\n<p>Now that Xata is set up in the project, you can query data with the utmost security and efficiency.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#creating-xata-api\"><\/a>Creating Xata API<\/h2>\n\n\n\n<p>To add an API key, you&#8217;ll go to your account settings, where you can add an API key. There you will be required to submit a name to generate a key. Because your key will only be shown to you once before becoming inaccessible for security reasons, ensure you copy it to a secure area. You can invalidate and create a new key if you misplace this one.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#setting-up-a-cloudinary-account\"><\/a>Setting Up a Cloudinary Account<\/h2>\n\n\n\n<p>Visit the&nbsp;<a href=\"https:\/\/cloudinary.com\/?utm_source=hackmamba&amp;utm_campaign=hackmamba-hackathon&amp;utm_medium=hackmamba-blog\">website<\/a>&nbsp;to sign up for a free account, then set up your Cloudinary account. You can sign up using GitHub, Gmail, or your email address.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>After signing up, you&#8217;ll be required to choose a role. In this case, you should select&nbsp;<strong>Developer<\/strong>&nbsp;and click continue.<\/li>\n\n\n\n<li>Next, you&#8217;ll be asked to select what your project is most likely to be. Select the first option and click&nbsp;<strong>Done<\/strong>.<\/li>\n\n\n\n<li>Navigate to your&nbsp;<strong>Dashboard<\/strong>. The dashboard contains the account details, which is the most critical area of the project.<\/li>\n\n\n\n<li>By default, Cloudinary assigns a random&nbsp;<strong>cloud name<\/strong>, which you can edit to a name of your choice. To edit your cloud name, click <strong>Settings<\/strong>&nbsp;(the clog icon at the top-left corner) and scroll to the bottom of the page.<\/li>\n\n\n\n<li>Enter the cloud name of your choice and click&nbsp;<strong>Save<\/strong>.<\/li>\n\n\n\n<li>Next, you need to set your upload preset. Still on your Settings page, at the top of the page, click <strong>Upload<\/strong>&nbsp;and scroll down to the section below.<\/li>\n\n\n\n<li>Click&nbsp;<strong>Add upload preset<\/strong>.<\/li>\n\n\n\n<li>Input your desired preset name, set the&nbsp;<strong>Signing mode<\/strong>&nbsp;to&nbsp;<strong>Unsigned<\/strong>, and click <strong>Save<\/strong>.<\/li>\n<\/ol>\n\n\n\n<p>Next, you&#8217;ll set up your Xata account.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setting Up the Xata Account<\/h2>\n\n\n\n<p>Visit the&nbsp;<a href=\"https:\/\/xata.io\/?utm_source=hackmamba&amp;utm_campaign=hackmamba-hackathon&amp;utm_medium=hackmamba-blog\">Xata<\/a>&nbsp;to register for free. You&#8217;ll see the&nbsp;<strong>Add a database<\/strong>&nbsp;card after signing up, where you&#8217;ll create your database.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Click the card, input your database name and click <strong>Create<\/strong>. A new card with your database name will appear next to the&nbsp;<strong>Add a database<\/strong>&nbsp;card.<\/li>\n\n\n\n<li>Next, you&#8217;ll need to create a table. Select your new database.<\/li>\n\n\n\n<li>Click&nbsp;<strong>Add a table<\/strong>&nbsp;in the sidebar below and insert your table name. You can also populate your table by clicking the&nbsp;<strong>Add a record<\/strong>&nbsp;button and filling in the desired details.<\/li>\n\n\n\n<li>For this project, you will need three tables; Users, Stores, and Products.<\/li>\n\n\n\n<li>The&nbsp;Users&nbsp;table should have the following columns:\n<ul class=\"wp-block-list\">\n<li><strong>id<\/strong>. The user&#8217;s unique id auto-generated by Xata.<\/li>\n\n\n\n<li><strong>first_name<\/strong>. The user&#8217;s first name.<\/li>\n\n\n\n<li><strong>last_name<\/strong>. The user&#8217;s last name.<\/li>\n\n\n\n<li><strong>email<\/strong>. The user&#8217;s email.<\/li>\n\n\n\n<li><strong>password<\/strong>. The user&#8217;s password.<\/li>\n\n\n\n<li><strong>username<\/strong>. The user&#8217;s display name.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>The&nbsp;Products&nbsp;table should have the following columns:\n<ul class=\"wp-block-list\">\n<li><strong>id<\/strong>. Xata auto-generated id.<\/li>\n\n\n\n<li><strong>name<\/strong>. Name of product.<\/li>\n\n\n\n<li><strong>price<\/strong>. Price of the product.<\/li>\n\n\n\n<li><strong>description<\/strong>. Short description of the product.<\/li>\n\n\n\n<li><strong>image_url<\/strong>. Image URL gotten from Cloudinary.<\/li>\n\n\n\n<li><strong>store_id<\/strong>. The store id.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Finally, the&nbsp;Store&nbsp;table should contain the following:\n<ul class=\"wp-block-list\">\n<li><strong>id<\/strong>. Xata auto-generated id<\/li>\n\n\n\n<li><strong>name<\/strong>. Store name.<\/li>\n\n\n\n<li><strong>owners_id<\/strong>. User id.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>Congratulations! You&#8217;ve completed the basic setup for Cloudinary and Xata. Next, you&#8217;ll insert and query data with Nextjs to Cloudinary and Xata.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#xata-and-nextjs\"><\/a>Xata and Nextjs<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#signing-up-users\"><\/a>Signing Up Users<\/h3>\n\n\n\n<p>Go to&nbsp;<code>\/pages\/api\/auth\/register.ts<\/code>.<\/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> { NextApiRequest, NextApiResponse } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\"<\/span>;\n<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> { getXataClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/..\/..\/utils\/xata.codegen\"<\/span>;\n\n\n<span class=\"hljs-keyword\">const<\/span> xata = getXataClient();\n<span class=\"hljs-keyword\">const<\/span> handler = nc().post(<span class=\"hljs-keyword\">async<\/span> (req: NextApiRequest, <span class=\"hljs-attr\">res<\/span>: NextApiResponse) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> record = <span class=\"hljs-keyword\">await<\/span> xata.db.Users.filter({\n    <span class=\"hljs-attr\">email<\/span>: req.body.email\n  }).getMany();\n  <span class=\"hljs-keyword\">if<\/span> (record.length !== <span class=\"hljs-number\">0<\/span>) {\n    res.status(<span class=\"hljs-number\">403<\/span>);\n    res.end();\n    <span class=\"hljs-keyword\">return<\/span>;\n  } <span class=\"hljs-keyword\">else<\/span> {\n    <span class=\"hljs-built_in\">console<\/span>.log(req.body)\n    <span class=\"hljs-keyword\">const<\/span> user = <span class=\"hljs-keyword\">await<\/span> xata.db.Users.create({\n      ...req.body,\n    });\n    <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">200<\/span>).json({ <span class=\"hljs-attr\">data<\/span>: user });\n  }\n});\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> handler;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The above code performs authentication for users when they try to sign up. First, the&nbsp;<code>Users<\/code>&nbsp;table is queried from the database and then filtered based on the email gotten from the client side. The result will be an array that&#8217;s passed to the&nbsp;<code>record<\/code>&nbsp;variable.<\/p>\n\n\n\n<p>Then we check if the record contains any data using&nbsp;<code>record.length<\/code>. If true, we&#8217;ll parse a 403 error code and end the process. If false, we proceed to create a new user.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#log-in-users\"><\/a>Logging in Users<\/h3>\n\n\n\n<p>Go to&nbsp;<code>\/pages\/api\/auth\/login.ts.<\/code><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { NextApiRequest, NextApiResponse } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\"<\/span>;\n<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> Router <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\/router\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { getXataClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/..\/..\/utils\/xata.codegen\"<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> xata = getXataClient();\n<span class=\"hljs-keyword\">const<\/span> handler = nc().post(<span class=\"hljs-keyword\">async<\/span> (req: NextApiRequest, <span class=\"hljs-attr\">res<\/span>: NextApiResponse) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> record = <span class=\"hljs-keyword\">await<\/span> xata.db.Users.filter({\n    <span class=\"hljs-attr\">email<\/span>: req.body.email,\n  }).getMany();\n\n  <span class=\"hljs-keyword\">if<\/span> (!record) {\n    <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">401<\/span>).json({ <span class=\"hljs-attr\">message<\/span>: <span class=\"hljs-string\">\"Invalid email\/password\"<\/span> });\n  } <span class=\"hljs-keyword\">else<\/span> <span class=\"hljs-keyword\">if<\/span> (record&#91;<span class=\"hljs-number\">0<\/span>].password !== req.body.password) {\n    <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">401<\/span>).json({ <span class=\"hljs-attr\">message<\/span>: <span class=\"hljs-string\">\"Invalid email\/password\"<\/span> });\n  } <span class=\"hljs-keyword\">else<\/span> {\n    <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">200<\/span>).json({ <span class=\"hljs-attr\">data<\/span>: record });\n  }\n});\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> handler;<\/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>Like the signup page, the Users table is also queried and filtered for the login page. If no data is found, an error message is passed. If a record is found, we parse the data.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#create-a-store\"><\/a>Creating a Store<\/h3>\n\n\n\n<p><code>\/pages\/api\/store\/index.ts<\/code><\/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> { NextApiRequest, NextApiResponse } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\"<\/span>;\n<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> { getXataClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/..\/..\/utils\/xata.codegen\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { decode } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"jsonwebtoken\"<\/span>;\n<span class=\"hljs-keyword\">const<\/span> xata = getXataClient();\n<span class=\"hljs-keyword\">const<\/span> handler = nc().post(<span class=\"hljs-keyword\">async<\/span> (req: NextApiRequest, <span class=\"hljs-attr\">res<\/span>: NextApiResponse) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> { name }: { <span class=\"hljs-attr\">name<\/span>: string } = req.body;\n  <span class=\"hljs-keyword\">const<\/span> jwt = req.cookies.frontier__jwt;\n  <span class=\"hljs-keyword\">const<\/span> decodedData = decode(jwt);\n  <span class=\"hljs-keyword\">const<\/span> accessToken = decodedData&#91;<span class=\"hljs-string\">\"0\"<\/span>].id;\n\n  <span class=\"hljs-keyword\">const<\/span> record = <span class=\"hljs-keyword\">await<\/span> xata.db.Store.create({\n    <span class=\"hljs-attr\">owners_id<\/span>: accessToken,\n    <span class=\"hljs-attr\">name<\/span>: name,\n  });\n  <span class=\"hljs-keyword\">if<\/span> (!accessToken &amp;&amp; record) {\n    res.end();\n    <span class=\"hljs-keyword\">return<\/span>;\n  }\n  res.status(<span class=\"hljs-number\">200<\/span>).json({\n    <span class=\"hljs-attr\">data<\/span>: record,\n  });\n});\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> handler;<\/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<p>To create a store, the above code retrieves the user&#8217;s (owner) id encoded with JSON web token (JWT) and passes it along with the desired store name.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#fetch-user-store\"><\/a>Fetching a User Store<\/h3>\n\n\n\n<p><code>\/pages\/api\/products\/index.ts<\/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> { NextApiRequest, NextApiResponse } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\"<\/span>;\n<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> { getXataClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/..\/..\/utils\/xata.codegen\"<\/span>;\n<span class=\"hljs-keyword\">const<\/span> xata = getXataClient();\n<span class=\"hljs-keyword\">import<\/span> { decode } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"jsonwebtoken\"<\/span>;\n<span class=\"hljs-keyword\">const<\/span> handler = nc().get(<span class=\"hljs-keyword\">async<\/span> (req: NextApiRequest, <span class=\"hljs-attr\">res<\/span>: NextApiResponse) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> jwt = req.cookies.frontier__jwt;\n  <span class=\"hljs-keyword\">const<\/span> decodedData = decode(jwt);\n  <span class=\"hljs-keyword\">const<\/span> accessToken = decodedData&#91;<span class=\"hljs-string\">\"0\"<\/span>].id;\n  <span class=\"hljs-keyword\">const<\/span> record = <span class=\"hljs-keyword\">await<\/span> xata.db.Store.filter({\n    <span class=\"hljs-attr\">owners_id<\/span>: accessToken,\n  }).getMany();\n  <span class=\"hljs-keyword\">if<\/span> (!record) {\n    res.end();\n    <span class=\"hljs-keyword\">return<\/span>;\n  }\n  res.status(<span class=\"hljs-number\">200<\/span>).json({\n    <span class=\"hljs-attr\">data<\/span>: record,\n  });\n});\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> handler;<\/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>The code above filters the Store table by the user&#8217;s id and returns every store owned by the user.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#post-a-product\"><\/a>Posting a Product<\/h3>\n\n\n\n<p><code>\/pages\/api\/store\/index.ts<\/code><\/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> { NextApiRequest, NextApiResponse } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\"<\/span>;\n<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> { getXataClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/..\/..\/utils\/xata.codegen\"<\/span>;\n<span class=\"hljs-keyword\">const<\/span> xata = getXataClient();\n<span class=\"hljs-keyword\">const<\/span> handler = nc().post(<span class=\"hljs-keyword\">async<\/span> (req: NextApiRequest, <span class=\"hljs-attr\">res<\/span>: NextApiResponse) =&gt; {\n  <span class=\"hljs-built_in\">console<\/span>.log(req.body);\n  <span class=\"hljs-keyword\">const<\/span> product = xata.db.Products.create({ ...req.body });\n  <span class=\"hljs-built_in\">console<\/span>.log(product);\n  <span class=\"hljs-keyword\">return<\/span> res.status(<span class=\"hljs-number\">200<\/span>).json({ <span class=\"hljs-attr\">data<\/span>: product });\n});\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> handler;<\/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<p>To create a product, the above code passes the information sent from the client form.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#fetch-user-product\"><\/a>Fetching a User Product<\/h3>\n\n\n\n<p><code>\/pages\/api\/stores\/index.ts<\/code><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { NextApiRequest, NextApiResponse } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\"<\/span>;\n<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> { getXataClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/..\/..\/utils\/xata.codegen\"<\/span>;\n<span class=\"hljs-keyword\">const<\/span> xata = getXataClient();\n<span class=\"hljs-keyword\">const<\/span> handler = nc().post(<span class=\"hljs-keyword\">async<\/span> (req: NextApiRequest, <span class=\"hljs-attr\">res<\/span>: NextApiResponse) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> { storeID } = req.body;\n  <span class=\"hljs-keyword\">const<\/span> record = <span class=\"hljs-keyword\">await<\/span> xata.db.Products.filter({\n    <span class=\"hljs-attr\">store_id<\/span>: storeID,\n  }).getMany();\n  <span class=\"hljs-keyword\">if<\/span> (!record) {\n    res.end();\n    <span class=\"hljs-keyword\">return<\/span>;\n  }\n  res.status(<span class=\"hljs-number\">200<\/span>).json({\n    <span class=\"hljs-attr\">data<\/span>: record,\n  });\n});\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> handler;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The code above filters the Product table based on the store&#8217;s id and returns every product owned by the store.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#cloudinary-and-nextjs\"><\/a>Cloudinary and Nextjs<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#uploading-file-to-cloudinary\"><\/a>Uploading a File to Cloudinary<\/h3>\n\n\n\n<p><code>\/pages\/app\/products\/new\/index.ts<\/code><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">\n<span class=\"hljs-keyword\">const<\/span> NewProduct = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> router = useRouter();\n  <span class=\"hljs-keyword\">const<\/span> &#91;file, setFile] = useState()\n  <span class=\"hljs-keyword\">const<\/span> &#91;image_url, setImage_url] = useState(<span class=\"hljs-string\">\"\"<\/span>)\n  <span class=\"hljs-keyword\">const<\/span> &#91;name, setName] = useState()\n  <span class=\"hljs-keyword\">const<\/span> &#91;price, setPrice] = useState()\n  <span class=\"hljs-keyword\">const<\/span> &#91;description, setDescription] = useState()\n\n  <span class=\"hljs-keyword\">const<\/span> cloudinary_url = <span class=\"hljs-string\">`https:\/\/api.cloudinary.com\/v1_1\/<span class=\"hljs-subst\">${process.env.CLOUD_NAME}<\/span>\/image\/upload`<\/span>;\n\n  <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handleSubmit<\/span>(<span class=\"hljs-params\">e<\/span>)<\/span>{\n    e.preventDefault()\n    <span class=\"hljs-keyword\">const<\/span> formData =  <span class=\"hljs-keyword\">new<\/span> FormData()\n    formData.append(<span class=\"hljs-string\">\"folder\"<\/span>, <span class=\"hljs-string\">\"Frontier store\"<\/span>)\n    formData.append(<span class=\"hljs-string\">\"file\"<\/span>, file)\n    formData.append(<span class=\"hljs-string\">\"upload_preset\"<\/span>, <span class=\"hljs-string\">`<span class=\"hljs-subst\">${process.env.UPLOAD_PRESET}<\/span>`<\/span>)\n    <span class=\"hljs-keyword\">await<\/span> fetch(cloudinary_url, {\n      <span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">\"POST\"<\/span>,\n      <span class=\"hljs-attr\">body<\/span>: formData\n    }) .then(<span class=\"hljs-function\">(<span class=\"hljs-params\">response<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">return<\/span> response.json();\n    })\n    .then(<span class=\"hljs-function\">(<span class=\"hljs-params\">data<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-comment\">\/\/ console.log(data)<\/span>\n      setImage_url(data.url)\n      setImage_url(<span class=\"hljs-function\">(<span class=\"hljs-params\">image_url<\/span>) =&gt;<\/span> {\n        product({name, price, image_url, description})\n        .then(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> router.push(<span class=\"hljs-string\">'\/app'<\/span>))\n        .catch(<span class=\"hljs-function\">(<span class=\"hljs-params\">err<\/span>) =&gt;<\/span> <span class=\"hljs-built_in\">console<\/span>.log(err));\n        <span class=\"hljs-keyword\">return<\/span> image_url\n      })\n    })\n    <span class=\"hljs-built_in\">console<\/span>.log(image_url)\n  }\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handleFileChange<\/span>(<span class=\"hljs-params\">e<\/span>)<\/span>{\n    setFile(e.target.files&#91;<span class=\"hljs-number\">0<\/span>])\n  }\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handleProductNameChange<\/span>(<span class=\"hljs-params\">e<\/span>)<\/span>{\n    setName(e.target.value)\n  }\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handleProductPriceChange<\/span>(<span class=\"hljs-params\">e<\/span>)<\/span>{\n    setPrice(e.target.value)\n  }\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handleProductDescriptionChange<\/span>(<span class=\"hljs-params\">e<\/span>)<\/span>{\n    setDescription(e.target.value)\n  }\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Layout<\/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\">{styles.main}<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span>&gt;<\/span>Create New Product<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">onSubmit<\/span>=<span class=\"hljs-string\">{handleSubmit}<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">InputField<\/span>\n              <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"file\"<\/span>\n              <span class=\"hljs-attr\">label<\/span>=<span class=\"hljs-string\">\"Product Image\"<\/span>\n              <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleFileChange}<\/span>\n              <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"image\"<\/span>\n              <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"image\"<\/span>\n              \/\/ <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{String(file)}<\/span>\n            \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">InputField<\/span>\n              <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span>\n              <span class=\"hljs-attr\">label<\/span>=<span class=\"hljs-string\">\"Product Name\"<\/span>\n              <span class=\"hljs-attr\">placeholder<\/span>=<span class=\"hljs-string\">\"Enter the product name\"<\/span>\n              <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleProductNameChange}<\/span>\n              <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"product_name\"<\/span>\n              <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"product_name\"<\/span>\n              <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{name}<\/span>\n            \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">InputField<\/span>\n              <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span>\n              <span class=\"hljs-attr\">label<\/span>=<span class=\"hljs-string\">\"Product Price\"<\/span>\n              <span class=\"hljs-attr\">placeholder<\/span>=<span class=\"hljs-string\">\"Enter the price for the product\"<\/span>\n              <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleProductPriceChange}<\/span>\n              <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"product_price\"<\/span>\n              <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"product_price\"<\/span>\n              <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{price}<\/span>\n            \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">textarea<\/span> <span class=\"hljs-attr\">placeholder<\/span>=<span class=\"hljs-string\">\"Describe the product\"<\/span> <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleProductDescriptionChange}<\/span> \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Button<\/span> <span class=\"hljs-attr\">label<\/span>=<span class=\"hljs-string\">\"Create product\"<\/span> <span class=\"hljs-attr\">theme<\/span>=<span class=\"hljs-string\">\"green\"<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"submit\"<\/span> \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/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\">Layout<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n};\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> NewProduct;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The above code aids in passing the image file to Cloudinary. The&nbsp;<code>handleFileChange()<\/code>&nbsp;function sets the&nbsp;<code>file<\/code>&nbsp;state with the image file from the input field. After filling in other fields, the submit button calls the&nbsp;<code>handleSubmit()<\/code>&nbsp;function when clicked. The&nbsp;<code>formData<\/code>&nbsp;is used to construct a set of key\/value pairs representing the required field for uploading media to Cloudinary.<\/p>\n\n\n\n<p>Then a POST request is made, passing the&nbsp;<code>cloudinary_url<\/code>, along with the&nbsp;<code>formData<\/code>. The response is parsed, and the URL for the image is set to state&nbsp;<code>image_url<\/code>. Next, all the information from the form is passed to the server side using the&nbsp;<code>product()<\/code>&nbsp;function, where they are inserted into the Product table.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#wrapping-up\"><\/a>Wrapping Up<\/h2>\n\n\n\n<p>In this blog post, you learned how to set up and use <a href=\"https:\/\/cloudinary.com\/\">Cloudinary<\/a> to upload and store media files and Xata to query data from your Next.js project. You also learned how to configure Xata on your project using the CLI. The project is available and accessible on GitHub.<\/p>\n\n\n\n<p>You can check out the&nbsp;<a href=\"https:\/\/frontier-xi.vercel.app\/\" target=\"_blank\" rel=\"noreferrer noopener\">live application<\/a>&nbsp;to get a feel for how the application works.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/dev.to\/hackmamba\/building-an-e-commerce-storefront-using-nextjs-cloudinary-and-xata-50pk#project-contributors\"><\/a>Project Contributors<\/h2>\n\n\n\n<p><strong>Akunne Pascal<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/Kodecheff\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/twitter.com\/meta_khal\" target=\"_blank\" rel=\"noreferrer noopener\">Twitter<\/a><\/li>\n<\/ul>\n\n\n\n<p><strong>Harcourt Hamsa<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/HarcourtHamsa\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/twitter.com\/harcourt_hamsa\" target=\"_blank\" rel=\"noreferrer noopener\">Twitter<\/a><\/li>\n<\/ul>\n\n\n<div class='c-callout  c-callout--inline-title c-callout--note'><strong class='c-callout__title'>Note:<\/strong> <p>This post was written for Hackmamba. Hackmamba partnered with with Cloudinary, Xata, and Uniform for a series of workshops to create technical blog posts, building optimized Jamstack products.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>As more and more people favor the convenience of online shopping, business owners turn to e-commerce platform builders, like Shopify, to sell more products. E-retail sales have surpassed 5.7 trillion dollars globally, and this number is only likely to rise in the upcoming years. In this blog post, you&#8217;ll earn how to integrate Xata and [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":31770,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[98,134,212],"class_list":["post-31766","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-e-commerce","tag-guest-post","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>Building an E-commerce Storefront Using Next.js, Cloudinary, and Xata<\/title>\n<meta name=\"description\" content=\"As more and more people favor the convenience of online shopping, business owners turn to e-commerce platform builders, like Shopify, to sell more\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building an E-commerce Storefront Using Next.js, Cloudinary, and Xata\" \/>\n<meta property=\"og:description\" content=\"As more and more people favor the convenience of online shopping, business owners turn to e-commerce platform builders, like Shopify, to sell more\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2023-11-08T20:22:37+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-01-24T02:23:15+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1699472047\/Web_Assets\/blog\/Blog-Hackmamba_Building_A_Storefront\/Blog-Hackmamba_Building_A_Storefront-jpeg?_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\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Building an E-commerce Storefront Using Next.js, Cloudinary, and Xata\",\"datePublished\":\"2023-11-08T20:22:37+00:00\",\"dateModified\":\"2025-01-24T02:23:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata\"},\"wordCount\":1362,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1699472047\/Web_Assets\/blog\/Blog-Hackmamba_Building_A_Storefront\/Blog-Hackmamba_Building_A_Storefront.jpeg?_i=AA\",\"keywords\":[\"E-commerce\",\"Guest Post\",\"Next.js\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2023\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata\",\"url\":\"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata\",\"name\":\"Building an E-commerce Storefront Using Next.js, Cloudinary, and Xata\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1699472047\/Web_Assets\/blog\/Blog-Hackmamba_Building_A_Storefront\/Blog-Hackmamba_Building_A_Storefront.jpeg?_i=AA\",\"datePublished\":\"2023-11-08T20:22:37+00:00\",\"dateModified\":\"2025-01-24T02:23:15+00:00\",\"description\":\"As more and more people favor the convenience of online shopping, business owners turn to e-commerce platform builders, like Shopify, to sell more\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1699472047\/Web_Assets\/blog\/Blog-Hackmamba_Building_A_Storefront\/Blog-Hackmamba_Building_A_Storefront.jpeg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1699472047\/Web_Assets\/blog\/Blog-Hackmamba_Building_A_Storefront\/Blog-Hackmamba_Building_A_Storefront.jpeg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building an E-commerce Storefront Using Next.js, Cloudinary, and Xata\"}]},{\"@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":"Building an E-commerce Storefront Using Next.js, Cloudinary, and Xata","description":"As more and more people favor the convenience of online shopping, business owners turn to e-commerce platform builders, like Shopify, to sell more","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata","og_locale":"en_US","og_type":"article","og_title":"Building an E-commerce Storefront Using Next.js, Cloudinary, and Xata","og_description":"As more and more people favor the convenience of online shopping, business owners turn to e-commerce platform builders, like Shopify, to sell more","og_url":"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata","og_site_name":"Cloudinary Blog","article_published_time":"2023-11-08T20:22:37+00:00","article_modified_time":"2025-01-24T02:23:15+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1699472047\/Web_Assets\/blog\/Blog-Hackmamba_Building_A_Storefront\/Blog-Hackmamba_Building_A_Storefront-jpeg?_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\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Building an E-commerce Storefront Using Next.js, Cloudinary, and Xata","datePublished":"2023-11-08T20:22:37+00:00","dateModified":"2025-01-24T02:23:15+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata"},"wordCount":1362,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1699472047\/Web_Assets\/blog\/Blog-Hackmamba_Building_A_Storefront\/Blog-Hackmamba_Building_A_Storefront.jpeg?_i=AA","keywords":["E-commerce","Guest Post","Next.js"],"inLanguage":"en-US","copyrightYear":"2023","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata","url":"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata","name":"Building an E-commerce Storefront Using Next.js, Cloudinary, and Xata","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1699472047\/Web_Assets\/blog\/Blog-Hackmamba_Building_A_Storefront\/Blog-Hackmamba_Building_A_Storefront.jpeg?_i=AA","datePublished":"2023-11-08T20:22:37+00:00","dateModified":"2025-01-24T02:23:15+00:00","description":"As more and more people favor the convenience of online shopping, business owners turn to e-commerce platform builders, like Shopify, to sell more","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1699472047\/Web_Assets\/blog\/Blog-Hackmamba_Building_A_Storefront\/Blog-Hackmamba_Building_A_Storefront.jpeg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1699472047\/Web_Assets\/blog\/Blog-Hackmamba_Building_A_Storefront\/Blog-Hackmamba_Building_A_Storefront.jpeg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/building-an-e-commerce-storefront-using-next-js-cloudinary-and-xata#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Building an E-commerce Storefront Using Next.js, Cloudinary, and Xata"}]},{"@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\/v1699472047\/Web_Assets\/blog\/Blog-Hackmamba_Building_A_Storefront\/Blog-Hackmamba_Building_A_Storefront.jpeg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/31766","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=31766"}],"version-history":[{"count":6,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/31766\/revisions"}],"predecessor-version":[{"id":36612,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/31766\/revisions\/36612"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/31770"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=31766"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=31766"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=31766"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}