Back to articles

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

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

Introduction

This article will guide you through building a basic e-commerce storefront using React, Next.js for server-side rendering, and Stripe for handling payments. We'll focus on the core components: displaying products and processing payments. This is a simplified example suitable for learning purposes.

Prerequisites

  • Node.js and npm or yarn installed
  • Stripe account (for API keys)

Setting up Next.js

First, create a new Next.js project:

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

Displaying Products

Create a components directory and a ProductCard.js file:

// components/ProductCard.js
import React from 'react';

const ProductCard = ({ product }) => {
  return (
    <div>
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      <button>Add to Cart</button>
    </div>
  );
};

export default ProductCard;

In your pages/index.js:

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

const products = [
  { id: 1, name: 'Awesome T-Shirt', price: 25 },
  { id: 2, name: 'Cool Mug', price: 15 },
];

const Home = () => {
  return (
    <div>
      <h1>Our Products</h1>
      {products.map((product) => (
        <ProductCard key={product.id} product={product} />
      ))}
    </div>
  );
};

export default Home;

Integrating Stripe

Install the Stripe library:

npm install @stripe/stripe-js @stripe/react-stripe-js

Create a .env.local file and add your Stripe publishable key:

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_YOUR_STRIPE_PUBLISHABLE_KEY

Create a pages/api/checkout_sessions.js file to handle creating Stripe checkout sessions:

// pages/api/checkout_sessions.js
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

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: 'Your Product',
              },
              unit_amount: 2000, // Amount 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) {
      res.status(err.statusCode || 500).json(err.message);
    }
  } else {
    res.setHeader('Allow', 'POST');
    res.status(405).end('Method Not Allowed');
  }
}

Important: You need to set STRIPE_SECRET_KEY in your environment variables. Never expose your secret key in your client-side code!

Update ProductCard.js to include a checkout button:

// components/ProductCard.js
import React from 'react';

const ProductCard = ({ product }) => {

  const handleCheckout = async () => {
    const response = await fetch('/api/checkout_sessions', {
      method: 'POST',
    });

    const data = await response.json();

    if (response.status === 303) {
      window.location.href = data.url;
    } else {
      console.error("Checkout failed");
    }
  };

  return (
    <div>
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      <button onClick={handleCheckout}>Buy Now</button>
    </div>
  );
};

export default ProductCard;

Create pages/success.js and pages/cancel.js for handling the success and cancel URLs. These can be simple pages that display a message to the user.

Conclusion

This provides a foundational understanding of building a serverless e-commerce storefront. You can expand on this by adding features like:

  • Shopping cart functionality
  • User authentication
  • Database integration for product management
  • More robust error handling