Back to articles

Building a Serverless E-commerce Storefront with Next.js and Stripe

AuthorMajd Muhtaseb05/22/202510 minutes
Building a Serverless E-commerce Storefront with Next.js and Stripe

Introduction

This article demonstrates how to build a basic serverless e-commerce storefront using Next.js and Stripe. We'll focus on the core components: displaying products and processing payments.

Setting up Next.js

First, create a new Next.js project:

npx create-next-app my-ecommerce-store
cd my-ecommerce-store

Displaying Products

Let's create a simple product listing. For simplicity, we'll hardcode product data. In a real application, you'd fetch this from a database or CMS.

Create a file components/ProductList.js:

// components/ProductList.js
const products = [
  { id: 1, name: "T-Shirt", price: 20 },
  { id: 2, name: "Mug", price: 10 },
  { id: 3, name: "Sticker", price: 5 },
];

const ProductList = () => (
  <ul>
    {products.map((product) => (
      <li key={product.id}>
        {product.name} - ${product.price}
      </li>
    ))}
  </ul>
);

export default ProductList;

Update pages/index.js:

// pages/index.js
import ProductList from '../components/ProductList';

const Home = () => {
  return (
    <div>
      <h1>Welcome to our Store!</h1>
      <ProductList />
    </div>
  );
};

export default Home;

Integrating Stripe

Install Stripe's JavaScript library:

npm install @stripe/stripe-js

Creating a Checkout Session

We'll need a serverless function (API route in Next.js) to create a Stripe Checkout Session. Create pages/api/checkout_sessions.js:

// pages/api/checkout_sessions.js
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
  apiVersion: '2023-10-16',
});

export default async function handler(req, res) {
  if (req.method === 'POST') {
    try {
      const session = await stripe.checkout.sessions.create({
        line_items: [
          {
            price_data: {
              currency: 'usd',
              product_data: {
                name: 'T-shirt', // Replace with dynamic product data
              },
              unit_amount: 2000, // Price in cents
            },
            quantity: 1,
          },
        ],
        mode: 'payment',
        success_url: `${req.headers.origin}/success`,
        cancel_url: `${req.headers.origin}/cancel`,
      });

      res.redirect(303, session.url);
    } catch (err) {
      console.error(err);
      res.status(500).json({ statusCode: 500, message: err.message });
    }
  } else {
    res.setHeader('Allow', 'POST');
    res.status(405).end('Method Not Allowed');
  }
}

Important:

  • Set STRIPE_SECRET_KEY in your .env.local file. Obtain this from your Stripe dashboard.
  • The success_url and cancel_url should point to pages you create in your Next.js application to handle successful and canceled payments.

Implementing the Checkout Button

Add a checkout button to your product list:

// components/ProductList.js (updated)
import { loadStripe } from '@stripe/stripe-js';

const products = [
  { id: 1, name: "T-Shirt", price: 20 },
  { id: 2, name: "Mug", price: 10 },
  { id: 3, name: "Sticker", price: 5 },
];

const ProductList = () => {
  const handleCheckout = async () => {
    const stripe = await loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY);
    const response = await fetch('/api/checkout_sessions', {
      method: 'POST',
    });
    const session = await response.json();

    if (response.ok) {
      stripe.redirectToCheckout({ sessionId: session.id });
    } else {
      console.error('Checkout failed:', session.message);
      alert('Checkout failed. Please try again.');
    }
  };

  return (
    <ul>
      {products.map((product) => (
        <li key={product.id}>
          {product.name} - ${product.price}
          <button onClick={handleCheckout}>Checkout</button>
        </li>
      ))}
    </ul>
  );
};

export default ProductList;

Important:

  • Set NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY in your .env.local file. Obtain this from your Stripe dashboard. Make sure this key is prefixed with NEXT_PUBLIC_ so that Next.js will expose it to the browser.

Conclusion

This is a basic implementation of a serverless e-commerce storefront using Next.js and Stripe. You can expand this by adding features like:

  • Fetching product data from a database or CMS.
  • Implementing user authentication.
  • Adding a shopping cart.
  • Handling shipping and taxes.

Remember to handle errors and security considerations carefully when building a production application.