Next.js E-commerce Solutions
Introduction
E-commerce has become an essential part of the modern business landscape, with online sales growing year after year. As a developer, building robust e-commerce solutions requires a framework that can handle complex functionality like product catalogs, shopping carts, user authentication, and payment processing—all while maintaining excellent performance and SEO capabilities.
Next.js stands out as an excellent choice for e-commerce applications thanks to its:
- Server-side rendering and static generation for improved SEO and performance
- API routes for secure server-side operations like payment processing
- Dynamic routing for product pages and categories
- Image optimization for fast-loading product images
- Incremental Static Regeneration to update content without rebuilding the entire site
In this guide, we'll explore the different e-commerce solutions available in the Next.js ecosystem, from fully-managed platforms to headless commerce APIs, helping you choose the right approach for your project.
Popular Next.js E-commerce Solutions
1. Next.js + Shopify
Shopify is one of the most popular e-commerce platforms, and it works excellently with Next.js through its Storefront API.
Getting Started with Shopify and Next.js
First, you'll need to install the required packages:
npm install @shopify/shopify-api shopify-buy
Then, create a Shopify client in a utility file:
// lib/shopify.js
import Client from 'shopify-buy';
const client = Client.buildClient({
domain: process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN,
storefrontAccessToken: process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN
});
export { client };
Fetching Products from Shopify
Here's a basic example of fetching products from Shopify in a Next.js page:
// pages/products.js
import { client } from '../lib/shopify';
import { useEffect, useState } from 'react';
export default function Products() {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchProducts = async () => {
const products = await client.product.fetchAll();
setProducts(products);
setLoading(false);
};
fetchProducts();
}, []);
if (loading) return <div>Loading...</div>;
return (
<div>
<h1>Products</h1>
<div className="products-grid">
{products.map(product => (
<div key={product.id} className="product-card">
<img
src={product.images[0].src}
alt={product.title}
width="200"
height="200"
/>
<h2>{product.title}</h2>
<p>${product.variants[0].price}</p>
</div>
))}
</div>
</div>
);
}
Benefits of Shopify with Next.js
- Managed infrastructure for inventory and order processing
- Robust admin dashboard for managing products
- Secure payment handling
- International shipping and tax calculations
- Next.js allows you to create a custom frontend experience
2. Next.js + Commerce.js
Commerce.js is a headless commerce API that provides all the backend functionality needed for an e-commerce store while giving you complete frontend flexibility.
Setting up Commerce.js with Next.js
Install the Commerce.js SDK:
npm install @chec/commerce.js
Create a Commerce.js client:
// lib/commerce.js
import Commerce from '@chec/commerce.js';
export const commerce = new Commerce(
process.env.NEXT_PUBLIC_COMMERCEJS_PUBLIC_KEY
);
Fetching Products and Managing Cart
// pages/index.js
import React, { useState, useEffect } from 'react';
import { commerce } from '../lib/commerce';
export default function Home() {
const [products, setProducts] = useState([]);
const [cart, setCart] = useState({});
const fetchProducts = async () => {
const { data } = await commerce.products.list();
setProducts(data);
};
const fetchCart = async () => {
const cart = await commerce.cart.retrieve();
setCart(cart);
};
const handleAddToCart = async (productId, quantity) => {
const { cart } = await commerce.cart.add(productId, quantity);
setCart(cart);
};
useEffect(() => {
fetchProducts();
fetchCart();
}, []);
return (
<div>
<h1>Products</h1>
<p>Cart items: {cart.total_items}</p>
<div className="products">
{products.map(product => (
<div key={product.id}>
<img src={product.media.source} alt={product.name} />
<h2>{product.name}</h2>
<p dangerouslySetInnerHTML={{ __html: product.description }}></p>
<p>{product.price.formatted_with_symbol}</p>
<button onClick={() => handleAddToCart(product.id, 1)}>
Add to Cart
</button>
</div>
))}
</div>
</div>
);
}
3. Next.js + Medusa
Medusa is an open-source headless commerce engine that provides a fully customizable e-commerce backend with a plugin architecture.
Setting up Medusa with Next.js
While Medusa requires a separate backend server, you can interact with it from your Next.js application using their JavaScript client:
npm install @medusajs/medusa-js
Create a Medusa client:
// lib/medusa-client.js
import { Medusa } from '@medusajs/medusa-js';
const medusaClient = new Medusa({
baseUrl: process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL
});
export default medusaClient;
Fetching Products and Categories
// pages/products.js
import { useEffect, useState } from 'react';
import medusaClient from '../lib/medusa-client';
export default function Products() {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchProducts = async () => {
const { products } = await medusaClient.products.list();
setProducts(products);
setLoading(false);
};
fetchProducts();
}, []);
if (loading) return <div>Loading...</div>;
return (
<div>
<h1>Products</h1>
<div className="products-grid">
{products.map(product => (
<div key={product.id} className="product-card">
{product.thumbnail && (
<img
src={product.thumbnail}
alt={product.title}
width="200"
/>
)}
<h2>{product.title}</h2>
<p>{product.price} USD</p>
</div>
))}
</div>
</div>
);
}
4. Other Notable Solutions
BigCommerce
BigCommerce offers a robust API for building headless commerce solutions with Next.js:
npm install node-bigcommerce
Saleor
Saleor is an open-source e-commerce platform that works well with Next.js through its GraphQL API:
npm install @apollo/client graphql
Next.js Commerce
The Next.js team created a starter kit called Next.js Commerce, which provides a production-ready template for building e-commerce sites with various backends:
npx create-next-app -e commerce
Real-World Example: Product Details Page
Let's build a product details page that demonstrates how to fetch product information, display it, and add items to a cart using Commerce.js:
// pages/products/[permalink].js
import { useState } from 'react';
import { commerce } from '../../lib/commerce';
export default function ProductPage({ product }) {
const [quantity, setQuantity] = useState(1);
const [loading, setLoading] = useState(false);
const [added, setAdded] = useState(false);
const handleAddToCart = async () => {
setLoading(true);
try {
await commerce.cart.add(product.id, quantity);
setAdded(true);
setTimeout(() => setAdded(false), 3000);
} catch (error) {
console.error('Error adding to cart', error);
} finally {
setLoading(false);
}
};
return (
<div className="product-detail">
<div className="product-image">
<img src={product.image.url} alt={product.name} />
</div>
<div className="product-info">
<h1>{product.name}</h1>
<p className="price">{product.price.formatted_with_symbol}</p>
<div dangerouslySetInnerHTML={{ __html: product.description }} />
<div className="actions">
<div className="quantity">
<button
onClick={() => setQuantity(q => Math.max(1, q - 1))}
disabled={quantity <= 1}
>
-
</button>
<span>{quantity}</span>
<button onClick={() => setQuantity(q => q + 1)}>+</button>
</div>
<button
className="add-to-cart"
onClick={handleAddToCart}
disabled={loading}
>
{loading ? 'Adding...' : 'Add to Cart'}
</button>
{added && <p className="success">Added to cart!</p>}
</div>
</div>
</div>
);
}
export async function getStaticProps({ params }) {
const { permalink } = params;
const product = await commerce.products.retrieve(permalink, {
type: 'permalink',
});
return {
props: {
product,
},
revalidate: 60, // Revalidate at most once per minute
};
}
export async function getStaticPaths() {
const { data: products } = await commerce.products.list();
return {
paths: products.map(product => ({
params: { permalink: product.permalink },
})),
fallback: 'blocking',
};
}
Performance Optimizations for E-commerce
E-commerce sites need to be fast to provide a good user experience and increase conversions. Here are some Next.js-specific optimizations:
1. Image Optimization
Use Next.js's Image component to automatically optimize product images:
import Image from 'next/image';
// Inside your product component
<Image
src={product.image.url}
alt={product.name}
width={600}
height={400}
layout="responsive"
priority={true} // For important above-the-fold images
/>
2. Incremental Static Regeneration (ISR)
ISR allows you to update static content without rebuilding the entire site. This is perfect for product pages with changing inventory:
// In your getStaticProps function
return {
props: { product },
revalidate: 60, // Update at most once per minute
}
3. Cart State Management
Use React Context to manage cart state across your application:
// context/CartContext.js
import { createContext, useContext, useState, useEffect } from 'react';
import { commerce } from '../lib/commerce';
const CartContext = createContext();
export function CartProvider({ children }) {
const [cart, setCart] = useState(null);
const [loading, setLoading] = useState(true);
const fetchCart = async () => {
try {
const cart = await commerce.cart.retrieve();
setCart(cart);
} catch (error) {
console.error('Error fetching cart', error);
} finally {
setLoading(false);
}
};
const addItem = async (productId, quantity) => {
const { cart } = await commerce.cart.add(productId, quantity);
setCart(cart);
return cart;
};
const updateItemQuantity = async (lineItemId, quantity) => {
const { cart } = await commerce.cart.update(lineItemId, { quantity });
setCart(cart);
return cart;
};
const removeItem = async (lineItemId) => {
const { cart } = await commerce.cart.remove(lineItemId);
setCart(cart);
return cart;
};
useEffect(() => {
fetchCart();
}, []);
return (
<CartContext.Provider value={{
cart,
loading,
addItem,
updateItemQuantity,
removeItem
}}>
{children}
</CartContext.Provider>
);
}
export function useCart() {
return useContext(CartContext);
}
Use this context in your _app.js
:
// pages/_app.js
import { CartProvider } from '../context/CartContext';
function MyApp({ Component, pageProps }) {
return (
<CartProvider>
<Component {...pageProps} />
</CartProvider>
);
}
export default MyApp;
Summary
Next.js provides a powerful foundation for building modern e-commerce applications thanks to its hybrid rendering capabilities, API routes, and performance optimizations. In this guide, we explored:
- Multiple e-commerce solutions that integrate with Next.js (Shopify, Commerce.js, Medusa, etc.)
- Basic implementation patterns for product listings, product details, and shopping carts
- Performance optimizations specific to e-commerce sites
- State management approaches for handling cart data
When choosing an e-commerce solution for your Next.js project, consider factors like:
- Do you need a full-featured admin dashboard?
- How much customization do you require?
- What's your budget for infrastructure and third-party services?
- Do you need features like inventory management, shipping calculations, and tax handling?
Whether you choose a fully-managed platform like Shopify or a headless solution like Commerce.js, Next.js provides the frontend flexibility to create fast, SEO-friendly, and conversion-optimized e-commerce experiences.
Additional Resources
- Next.js Commerce Official Template
- Shopify Storefront API Documentation
- Commerce.js Documentation
- Medusa Documentation
- Next.js Image Optimization Guide
Exercises
- Build a product listing page that fetches products from an e-commerce API of your choice.
- Implement a shopping cart using React Context and local storage.
- Create a checkout flow that collects shipping and payment information.
- Add product filtering and searching functionality to your product listing page.
- Implement product variants (size, color, etc.) on a product detail page.
By combining Next.js with one of these e-commerce solutions, you'll be well-equipped to build modern, high-performance online stores that provide excellent user experiences and convert visitors into customers.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)