Shopify + Next.js + Tailwind CSS: Modern eCommerce
Tags: nextjs, graphql, shopify, react
Published: 2021-09-02 15:34:11

 *Article brought to you by [buildnextshop.com](https://www.buildnextshop.com)*

In the last couple years, we have all gotten extremely comfortable with online shopping. This has pushed e-commerce brands to invest heavily in their online shopping experience. Shopify merchants have seen record growth in 2020 and 2021, driving the demand for Shopify developers. Many Shopify merchants are moving away from themes and starting to venture into headless e-commerce solutions. 

In this article I will be showing you the basics of setting up a headless e-commerce store using Shopify GraphQL Storefront API with Next.js as the frontend framework and tailwind CSS for styling. 

Next.js allows us to create blazing fast stores using static site generation, which is a perfect fit for e-commerce. 

Let's get started:

### 1. Setup Next.js Project with Tailwind CSS

There are many ways to set up a Next.js project but for our project this one is the fastest. 

```
npx create-next-app -e with-tailwindcss build-next-shop
cd build-next-shop
```


### 2. Set up Shopify Partners account and create a new store

Navigate to [Shopify Partners](https://www.shopify.com/partners) and create your Shopify Partners account (if you don't have one already).

Then, navigate to the Stores tab on the left-hand side and create a new store. 

Among other benefits, a Partners account will allow you to easily manage stores and have unlimited time to work on them before transferring to a client. 

### 3. Connect Shopify store to Next.js app


Navigate to the Apps tab in your store and hit the "Manage private apps" link at the bottom:

![Shopify manage private apps](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ygaeq08a34dcvo2oa5yu.png)

Accept the terms and conditions, name your private app "Next.js Connection" and enter your email address. Then scroll down and check **"Allow this app to access your storefront data using using the Storefront API"**.

![Storefront API Shopify](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5dlos7xyb03genog0ima.png)

Create .env.local file in the root folder of your Next.js app and add these variables:

```
SHOPIFY_STOREFRONT_ACCESSTOKEN='storefront api access token'
SHOPIFY_STORE_DOMAIN='yourstore.myshopify.com'
```

(not all files/folders shown)
```
build-next-shop
 ┣ node_modules
 ┣ pages
 ┣ public
 ┣ .env.local *
 ┗ package.json
....
```

### 4. Install Shopify GraphiQL App

Navigate to [Shopify GraphiQL App](https://shopify-graphiql-app.shopifycloud.com/), scroll to the bottom, hit "Select all" scopes for Storefront API access, and install the Shopify GraphiQL app that will help you to test your queries before you use them in your app.

(Before proceeding with this step, add some sample products to your store and make sure they are available for the GraphiQL App sales channel). 

![Adding Products](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gmjraf7lyluehsfvailz.png)

Now open the GraphiQL app, choose the Storefront API schema and paste this into the query field:

```
{
  products(first:5) {
    edges {
      node {
        id
      }
    }
  }
}
```

![Shopify GraphiQL app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eerkv9md5lry74yvumup.png)

Congrats! You made your first Storefront API query!

### 5. Fetching Products in Next.js Storefront

Inside your Next.js app, create a lib folder in the root directory and create a shopify.js file inside of it. 

(not all files/folders shown)
```
build-next-shop
 ┣ lib
 ┃ ┗ shopify.js *
 ┣ node_modules
 ┣ pages
 ┣ public
 ┣ .env.local
 ┗ package.json
....
```

Fill out shopify.js:

```
const domain = process.env.SHOPIFY_STORE_DOMAIN
const storefrontAccessToken = process.env.SHOPIFY_STOREFRONT_ACCESSTOKEN

async function ShopifyData(query) {
  const URL = `https://${domain}/api/2021-07/graphql.json`

  const options = {
    endpoint: URL,
    method: "POST",
    headers: {
      "X-Shopify-Storefront-Access-Token": storefrontAccessToken,
      "Accept": "application/json",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ query })
  }

  try {
    const data = await fetch(URL, options).then(response => {
      return response.json()
    })

    return data
  } catch (error) {
    throw new Error("Products not fetched")
  }
}

export async function getAllProducts() {
  const query = `
  {
  products(first: 25) {
    edges {
      node {
        id
        title
        handle
        priceRange {
          minVariantPrice {
            amount
          }
        }
        images(first: 5) {
          edges {
            node {
              originalSrc
              altText
            }
          }
        }
      }
    }
  }
}
`

  const response = await ShopifyData(query)

  const allProducts = response.data.products.edges ? response.data.products.edges : []

  return allProducts
}
```

What we are doing here: 
1. Creating a function called ShopifyData that will accept a query. 
2. ShopifyData it will make a POST request to the Shopify Storefront GraphQL API using the set headers and return the json response. 
3. ShopifyData function will return the data to the getAllProducts function which will set it equal to the allProducts variable. 


### 6. Displaying Products on homepage

Inside your index.js file:

```
import { getAllProducts } from "../lib/shopify"

export default function Home({ products }) {

  return (
    <div className="bg-white">
      <div className="max-w-2xl mx-auto py-16 px-4 sm:py-24 sm:px-6 lg:max-w-7xl lg:px-8">
        <h2 className="text-2xl font-extrabold text-gray-900 mb-6">
          Products
        </h2>
        <div className="grid grid-cols-1 gap-y-10 gap-x-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8">
         {
            products.map(product => (
              <ProductCard key={product.node.id} product={product} />
            ))
          }
       </div>
      </div>
    </div>
  )
}

export async function getStaticProps() {
  const products = await getAllProducts()

  return {
    props: { products }, // will be passed to the page component as props
  }
}
```

Create a ProductCard.js component in a new folder called components:

```
build-next-shop
 ┣ components
 ┃ ┗ ProductCard.js *
 ┣ lib
 ┣ node_modules
 ┣ pages
 ┣ public
 ┣ .env.local
 ┗ package.json
....
```

Then inside of ProductCard.js
```
import Link from 'next/link'
import Image from 'next/image'
import { formatter } from '../utils/helpers'

const ProductCard = ({ product }) => {
  const { handle, title } = product.node

  const { altText, originalSrc } = product.node.images.edges[0].node

  const price = product.node.priceRange.minVariantPrice.amount

  return (
    <Link
      href={`/products/${handle}`}
    >
      <a className="group">
        <div className="w-full bg-gray-200 rounded-3xl overflow-hidden">
          <div className="relative group-hover:opacity-75 h-72">
            <Image 
              src={originalSrc}
              alt={altText}
              layout="fill"
              objectFit="cover"
            />
          </div>
        </div>
        <h3 className="mt-4 text-lg font-medium text-gray-900">{title}</h3>
        <p className="mt-1 text-sm text-gray-700">{formatter.format(price)}</p>
      </a>
    </Link>
  )
}

export default ProductCard
```

What's happening here:
1. We are using the [getStaticProps](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) function provided to us by Next.js to prefetch all the products from the getAllProducts function from our shopify.js file.

2. Passing the products as a prop to our homepage function.
3. Creating a ProductCard.js to display a single product card. 
4. Mapping over the products and displaying the ProductCard.js for each one. 


### Congratulations! You just created your basic Shopify Next.js Storefront. 

#### Next Steps:

1. Dynamic product pages using the [getStaticPaths](https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation) Next.js function. 
2. Create add to cart functionality using React Context for cart state management.
3. Deploy to Vercel. 

Sample Starter Project: https://github.com/iskurbanov/shopify-next.js-tailwind

Checkout the example website and full tutorial at [BuildNextShop.com](https://www.buildnextshop.com) where we create a fully production ready Shopify Headless store using Next.js!