Integrating Shopify with Gatsby allows you to create a fast, dynamic, and highly customisable storefront.
First, you need to create a new Gatsby project. If you don't have Gatsby CLI installed, you can install it globally using npm or yarn:
npm install -g gatsby-cli
Create a new Gatsby project:
gatsby new gatsby-shopify-store
cd gatsby-shopify-store
Install the gatsby-source-shopify plugin and other necessary dependencies:
npm install gatsby-source-shopify dotenv gatsby-plugin-react-helmet
Log in to your Shopify Admin Panel:
Locate Your Store Name:
Navigate to Apps:
Manage Private Apps:
Create a New Private App:
Configure Your Private App:
Set API Permissions:
Save Your Private App:
Copy the Storefront API Access Token:
Create a .env file in the root of your project and add your Shopify store details, ensure these start with GATSBY_ otherwise you will have issues:
GATSBY_SHOPIFY_STORE_NAME=your-store-name.myshopify.com
GATSBY_SHOPIFY_ACCESS_TOKEN=your-storefront-access-token
Update your gatsby-config.js file to include the gatsby-source-shopify plugin:
require("dotenv").config({
path: `.env`,
});
module.exports = {
siteMetadata: {
title: "Gatsby Shopify Store",
},
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-shopify`,
options: {
shopName: process.env.GATSBY_SHOPIFY_STORE_NAME,
accessToken: process.env.GATSBY_SHOPIFY_ACCESS_TOKEN,
shopifyConnections: ["collections"],
downloadImages: false,
apiVersion: "2024-01",
},
},
],
};
Once you have configured the plugin, you can fetch data from your Shopify store using GraphQL. Start your development server:
gatsby develop
Open the GraphiQL interface at http://localhost:8000/___graphql and run the following query to fetch products:
{
allShopifyProduct {
nodes {
shopifyId
handle
title
vendor
featuredImage {
src
}
variants {
shopifyId
title
image {
src
}
price
}
priceRangeV2 {
maxVariantPrice {
amount
}
}
descriptionHtml
productType
metafields {
namespace
key
value
}
}
}
}
`);
To manage the state of your store, such as cart and checkout, create a StoreContext.js file in the src/context directory:
import React, { useState, createContext, useEffect } from 'react';
import Client from 'shopify-buy';
const client = Client.buildClient({
domain: process.env.GATSBY_SHOPIFY_STORE_NAME,
storefrontAccessToken: process.env.GATSBY_SHOPIFY_ACCESS_TOKEN,
});
const defaultValues = {
cart: [],
client,
checkout: {
lineItems: [],
},
updateCheckout: () => {},
};
export const StoreContext = createContext(defaultValues);
const StoreProvider = ({ children }) => {
const [checkout, setCheckout] = useState(defaultValues.checkout);
useEffect(() => {
const initializeCheckout = async () => {
const newCheckout = await client.checkout.create();
setCheckout(newCheckout);
};
initializeCheckout();
}, []);
const updateCheckout = (newCheckout) => {
setCheckout(newCheckout);
};
return (
<StoreContext.Provider value={{ ...defaultValues, checkout, updateCheckout }}>
{children}
</StoreContext.Provider>
);
};
export default StoreProvider;
Wrap your root element with the StoreProvider in gatsby-browser.js and gatsby-ssr.js:
import React from "react";
import StoreProvider from "./src/context/StoreContext";
export const wrapRootElement = ({ element }) => (
<StoreProvider>{element}</StoreProvider>
);
Create Product and Cart Components
import React, { useContext } from 'react';
import { graphql, useStaticQuery } from 'gatsby';
import { StoreContext } from '../context/StoreContext';
const ProductListing = () => {
const data = useStaticQuery(graphql`
query {
allShopifyProduct {
nodes {
shopifyId
handle
title
vendor
featuredImage {
src
}
variants {
shopifyId
title
image {
src
}
price
}
priceRangeV2 {
maxVariantPrice {
amount
}
}
descriptionHtml
productType
metafields {
namespace
key
value
}
}
}
}
`);
const { client, checkout, updateCheckout } = useContext(StoreContext);
const addToCart = async (variantId) => {
const lineItemsToAdd = [
{
variantId,
quantity: 1,
},
];
const newCheckout = await client.checkout.addLineItems(checkout.id, lineItemsToAdd);
updateCheckout(newCheckout);
};
return (
<div>
{data.allShopifyProduct.nodes.map((product) => (
<div key={product.shopifyId}>
<h2>{product.title}</h2>
<div dangerouslySetInnerHTML={{ __html: product.descriptionHtml }} />
{product.featuredImage && (
<img src={product.featuredImage.src} alt={product.title} />
)}
<p>{product.variants[0].price}</p>
<button onClick={() => addToCart(product.variants[0].shopifyId)}>
Add to Cart
</button>
</div>
))}
</div>
);
};
export default ProductListing;
Cart Component:
import React, { useContext } from 'react';
import { StoreContext } from '../context/StoreContext';
const Cart = () => {
const { checkout } = useContext(StoreContext);
return (
<div>
<h2>Cart</h2>
{checkout.lineItems.length ? (
checkout.lineItems.map((item) => (
<div key={item.id}>
<p>{item.title}</p>
<p>{item.quantity}</p>
<p>{item.variant.price}</p>
</div>
))
) : (
<p>Your cart is empty</p>
)}
</div>
);
};
export default Cart;
Finally, use the ProductListing and Cart components in your pages.
import React from 'react';
import ProductListing from '../components/ProductListing';
import Cart from '../components/Cart';
const IndexPage = () => (
<div>
<h1>Welcome to the Gatsby Shopify Store</h1>
<ProductListing />
<Cart />
</div>
);
export default IndexPage;
By following these steps, you have set up a Gatsby project integrated with Shopify, created a context for managing state, and built basic components for displaying products and a cart. This setup provides a strong foundation for building a dynamic, high-performance e-commerce site with Gatsby and Shopify.