Design+Code logo

Quick links

Suggested search

Shopify setup

If you haven't already, I highly encourage you to follow the first part of this tutorial , where you'll learn how to setup a Shopify store, add products to your store, and get a password to connect your Gatsby website to Shopify.

Completed project code

You can find the completed project code on Github at https://github.com/stephdiep/gatsby-shopify-tutorial . You can also download the source files, but remember to add your own password and storeUrl in the .env file for the project to build successfully. You can view the live demo at https://gatsby-shopify-tutorial.netlify.app/.

Install the plugin

Next, we'll need to install the gatsby-source-shopify plugin. In the Terminal, run the following command.

npm install gatsby-source-shopify

Let's add the password we copied from Shopify and our storeUrl (which is your-store-name.myshopify.com ), in an environment file - so we don't commit them to Github, as it's a big security flaw. Create a .env file, and add your password and storeUrl in it.

GATSBY_SHOPIFY_PASSWORD=shppa_a59ejcnvk2l29jkdmcn35skw
GATSBY_SHOPIFY_STORE_URL=designcode-tutorial.myshopify.com

Remember to change the password and the storeUrl to the ones from your Shopify account. We'll need to configure the plugin to connect with our Shopify account in the gatsby-config.js file. In the plugins array, add the gatsby-source-shopify plugin and pass in your app password , along with your storeUrl , to the options object.

// gatsby-config.js

require("dotenv").config()

module.exports = {
  plugins: [
    {
      resolve: "gatsby-source-shopify",
      options: {
        password: process.env.GATSBY_SHOPIFY_PASSWORD,
        storeUrl: process.env.GATSBY_SHOPIFY_STORE_URL,
      },
    },
  ],
}

Before continuing, we need to make sure that the setup is correct, and the app compiles successfully. Run your development server to verify that. If the app built successfully, move on to the next step.

gatsby develop

If you run into an error saying that your password and storeUrl are required, and you added them both in the .env file, just add require("dotenv").config() at the top of your gatsby-config.js file.

Querying the products

Fetching the products from Shopify is quite easy, as it's simply a GraphQL query. With your development server running, head over to the Gatsby GraphiQL interface ( http://localhost:8000/___graphql ) and we'll query all of our products with the following query. To query all the Shopify products, we'll use the allShopifyProduct node.

query MyQuery {
  allShopifyProduct {
    nodes {
      title
      handle
      variants {
				shopifyId
			}
      priceRangeV2 {
        maxVariantPrice {
          amount
        }
      }
      description
      images {
        src
      }
    }
  }
}

Click on the Play button and once you're satisfied with the results you see on the right side panel, copy your entire GraphQL query.

GraphQL Query for allShopifyProduct We'll create a products page, listing all the products we queried with the GraphQL query above. In a new products.js file, under the src > pages folder, define your Products component.

// src/pages/products.js

const Products = () => {
	return <div></div>
}

export default Products

Import React and graphql from gatsby at the top.

// src/pages/products.js

import React from "react"
import { graphql } from "gatsby"

Right below our export default , we'll add the GraphQL query we tested before.

// src/pages/products.js

export const query = graphql`
	{
		allShopifyProduct {
			nodes {
				title
				handle
				variants {
        	shopifyId
      	}
				priceRangeV2 {
					maxVariantPrice {
						amount
					}
				}
				description
				images {
					src
				}
			}
		}
	}
`

By adding this query in the Products.js file, we can access it with the data props we'll pass to our Products component.

// src/pages/products.js

const Products = ({ data }) => {
	console.log(data)
	return <div></div>
}

export default Products

We're console logging the data, and you should see the allShopifyProduct object printed on the console when navigating to the /products page. The products page should be a blank page now, but we'll fill it soon with all the products data.

GraphQL query response in the console Now, let's create a ProductCard component. Each product card will accept a product as a prop, and it'll display all the information of that product. Remember to npm install styled-components if you plan on using the ProductCard below.

// src/components/ProductCard.js

import React from 'react'
import styled from "styled-components"

const ProductCard = ({ product }) => {

  return (
    <Wrapper>
      <AddButton onClick={() => alert("Added to cart!")}><p>+</p></AddButton>
      <ContentWrapper>
        <Image src={product.images[0]?.src} />
        <TextWrapper>
          <Title>{product.title}</Title>
          <Price>{product.priceRangeV2.maxVariantPrice.amount}0$</Price>
        </TextWrapper>
      </ContentWrapper>
    </Wrapper>
  )
}

export default ProductCard

const Wrapper = styled.div`
  display: grid;
  justify-content: center;
  align-items: center;
  width: 200px;
  border-radius: 20px;

  gap: 10px;
  cursor: pointer;
  position: relative;
  box-shadow: 0px 20px 40px rgba(52, 53, 99, 0.2),
    0px 1px 3px rgba(0, 0, 0, 0.05);
`

const ContentWrapper = styled.div``

const Image = styled.img`
  width: 200px;
  height: 300px;
  object-fit: cover;
  border-radius: 20px;
  margin: 0;
`

const TextWrapper = styled.div`
  position: absolute;
  bottom: 0px;
  left: 0px;
  border-radius: 0 0 20px 20px;
  background: rgba(255, 255, 255, 0.2);
  width: 200px;
  padding: 10px 0;
  backdrop-filter: blur(40px);
`

const Title = styled.p`
  font-weight: 600;
  text-align: center;
  margin: 0;
  color: #014c40;
`

const Price = styled.p`
  font-weight: normal;
  text-align: center;
  margin: 0;
`

const AddButton = styled.div`
  position: absolute;
  top: 20px;
  right: 20px;
  background: #014c40;
  padding: 10px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;

  :hover {
    transform: scale(1.2);
    transition: 0.2s;
  }

  p {
    margin: 0;
    color: white;
    font-weight: bold;
  }
`

Back in Products.js , we'll iterate over the products we got from the GraphQL query and, for each product, we'll display the ProductCard . Remember to import ProductCard in Product.js.

// src/pages/Products.js
import ProductCard from "../components/ProductCard"

const Products = ({ data }) => {
	const { nodes } = data.allShopifyProduct

	return (
			<div>
				{nodes?.map((product, index) => (<ProductCard key={index} product={product} />))}
			</div>)
}

Create a product page

We'll need to create a template for each product we have in our store, since each one of them will have their own page. Let's create a templates folder under the src folder. In the templates folder, we'll add a new file called product.js . This is where we'll create our product page template. For now, let's just add the product title and its description on the page. This template will accept a pageContext prop, and we'll be able to get the product object from pageContext.

// src/templates/product.js

import React from "react"

const ProductTemplate = ({ pageContext }) => {
  const { product } = pageContext
  return (
    <div>
      <h1>{product.title}</h1>
      <p>{product.description}</p>
    </div>
  )
}

export default ProductTemplate

Head over to the gatsby-node.js file. Copy and paste the following code. This code will query all Shopify products and, for each one, create a unique page with the handle field, using the product.js template we just created.

const path = require(`path`)

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions

	// Query for all products in Shopify
  const result = await graphql(`
    query {
      allShopifyProduct {
        edges {
          node {
            title
            handle
            variants {
              shopifyId
            }
            priceRangeV2 {
              maxVariantPrice {
                amount
              }
            }
            description
            images {
              src
            }
          }
        }
      }
    
    }
  `)

  // Iterate over all products and create a new page using a template
  // The product "handle" is generated automatically by Shopify
  result.data.allShopifyProduct.edges.forEach(({ node }) => {
    createPage({
      path: `/products/${node.handle}`,
      component: path.resolve(`./src/templates/product.js`),
      context: {
        product: node,
      },
    })
  })
}

Now, since we changed our gatsby-node.js file, we need to restart the server. In the Terminal, stop the server with Control (^) + C , then restart the server.

gatsby develop

Link product card to product page

Head back to the ProductCard.js file. We'll add an onClick event on the card, so when the user clicks on the card, it'll lead them to the product page. Import navigate from gatsby-link , and add the onClick event on the ContentWrapper.

// src/components/ProductCard.js

import { navigate } from 'gatsby-link'

const ProductCard = ({ product }) => {
  return (
    <Wrapper>
			{ /* Add button here... */ }
      <ContentWrapper onClick={() => navigate(`${product.handle}`)}>
				{ /* Card content... */ }
      </ContentWrapper>
    </Wrapper>  )
}

Now let's test it out. Go to the products page, and click on any card. You should them land on a non-styled product page, and the URL should be /products/product-handle . We'll be styling this page right away!

Default product page template without styling Find below the product show page styled using styled-components. You can use this one, or code your own!

import { navigate } from "gatsby-link"
import React from "react"
import styled from "styled-components"

import Layout from "../components/layout"
import PrimaryButton from "../components/PrimaryButton"

const ProductTemplate = ({ pageContext }) => {
  const { product } = pageContext

  return (
    <Layout>
      <BackButton onClick={() => navigate(-1)}>{"< "} Back</BackButton>
      <Wrapper>
        <Image src={product.images[0]?.src} />
        <InfoContainer>
          <Title>{product.title}</Title>
          <Subtitle>{product.priceRangeV2.maxVariantPrice.amount}0$</Subtitle>
          <p>{product.description}</p>
          <InputForm>
            <Subtitle><label htmlFor="qty">Quantity:</label></Subtitle>
            <Input placeholder="1" id="qty" type="number" defaultValue={1} />
          </InputForm>
          <PrimaryButton text="Add to cart" onClick={() => alert("Added to cart!")} />
        </InfoContainer>
      </Wrapper>
    </Layout>
  )
}

export default ProductTemplate

const BackButton = styled.p`
  cursor: pointer;
  color: #014c40;
  margin-left: 40px;
  font-size: 14px;
  font-weight: 600;
`

const Wrapper = styled.div`
  margin: 40px;
  display: grid;
  grid-template-columns: 400px auto;
  gap: 40px;
`

const Image = styled.img`
  width: 400px;
  height: 500px;
  border-radius: 30px;
	object-fit: cover;
`

const InfoContainer = styled.div`
  display: grid;
  align-items: flex-start;
  height: fit-content;
  gap: 10px;

  p {
    margin: 0;
  }
`

const Title = styled.h1`
  margin: 0;
`

const Subtitle = styled.p`
  font-weight: bold;
  max-width: 500px;
`

const InputForm = styled.form`
  display: grid;
  grid-template-columns: repeat(2, auto);
  width: fit-content;
  gap: 20px;
  align-items: center;
  gap: 10px;
`

const Input = styled.input`
  border-radius: 20px;
  border: 2px solid rgba(0,0,0,0.3);
  padding: 10px 20px;
  max-width: 80px;
  font-size: 12px;
  :focus {
    outline: none;
    outline-color: #014c40;
  }
`

Upcoming

Great, we now created a basic working e-commerce website: we have our products list and a unique page for each product. The only thing that's left is to implement the checkout process. In the (upcoming) last part of this tutorial, we'll be covering that. See you in the next section!

Learn with videos and source files. Available to Pro subscribers only.

Purchase includes access to 50+ courses, 320+ premium tutorials, 300+ hours of videos, source files and certificates.

BACK TO

Gatsby and Shopify Part 1

READ NEXT

Gatsby and Shopify Part 3

Templates and source code

Download source files

Download the videos and assets to refer and learn offline without interuption.

check

Design template

check

Source code for all sections

check

Video files, ePub and subtitles

Browse all downloads