Building E-Commerce Platforms with Next.js
E-commerce demands high performance, reliability, and excellent UX. Building Floral Radiance taught me valuable lessons about creating production-ready online stores.
Architecture Overview
Technology Stack
- Frontend: Next.js with TypeScript and Ant Design
- Backend: Express.js with Node.js
- Database: MySQL with Prisma ORM
- Payment: Stripe or SSLCommerz integration
- Storage: Cloudinary for image management
Core Features Implementation
Product Catalog System
// lib/products.ts
interface Product {
id: number;
title: string;
description: string;
price: number;
images: string[];
stock: number;
category: string;
createdAt: Date;
}
export async function getProducts(
category?: string,
sortBy?: "price" | "newest",
): Promise<Product[]> {
const query = new URLSearchParams();
if (category) query.append("category", category);
if (sortBy) query.append("sort", sortBy);
const response = await fetch(`/api/products?${query}`);
return response.json();
}Shopping Cart Management
// context/CartContext.tsx
import { createContext, useContext, useState } from "react";
interface CartItem {
productId: number;
quantity: number;
price: number;
}
interface CartContextType {
items: CartItem[];
addItem: (item: CartItem) => void;
removeItem: (productId: number) => void;
updateQuantity: (productId: number, quantity: number) => void;
total: number;
}
const CartContext = createContext<CartContextType | null>(null);
export function CartProvider({ children }: { children: React.ReactNode }) {
const [items, setItems] = useState<CartItem[]>([]);
const total = items.reduce((sum, item) => sum + item.price * item.quantity, 0);
return (
<CartContext.Provider
value={{
items,
addItem: (item) => setItems([...items, item]),
removeItem: (id) => setItems(items.filter((i) => i.productId !== id)),
updateQuantity: (id, qty) =>
setItems(
items.map((i) => (i.productId === id ? { ...i, quantity: qty } : i))
),
total,
}}
>
{children}
</CartContext.Provider>
);
}
export const useCart = () => {
const context = useContext(CartContext);
if (!context) throw new Error("useCart must be used within CartProvider");
return context;
};Payment Integration
// pages/api/checkout.ts
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export default async function handler(req, res) {
if (req.method !== "POST") return res.status(405).end();
const { items } = req.body;
const session = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
line_items: items.map((item: CartItem) => ({
price_data: {
currency: "usd",
product_data: {
name: item.productName,
},
unit_amount: Math.round(item.price * 100),
},
quantity: item.quantity,
})),
mode: "payment",
success_url: `${process.env.NEXTAUTH_URL}/success`,
cancel_url: `${process.env.NEXTAUTH_URL}/cart`,
});
res.json({ sessionId: session.id });
}Database Schema for E-Commerce
// schema.prisma
model Product {
id Int @id @default(autoincrement())
title String
description String
price Decimal
stock Int
images String[]
category Category @relation(fields: [categoryId], references: [id])
categoryId Int
orders Order[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Order {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id])
userId Int
products Product[]
total Decimal
status String
createdAt DateTime @default(now())
}
model Category {
id Int @id @default(autoincrement())
name String
products Product[]
}Performance Optimization for E-Commerce
Image Optimization
// components/ProductImage.tsx
import Image from "next/image";
export function ProductImage({ src, alt }: { src: string; alt: string }) {
return (
<Image
src={src}
alt={alt}
width={500}
height={500}
placeholder="blur"
blurDataURL="data:image/jpeg,..."
quality={85}
/>
);
}Search and Filtering
// pages/api/products/search.ts
export default async function handler(req, res) {
const { q, minPrice, maxPrice, category } = req.query;
const products = await prisma.product.findMany({
where: {
AND: [
q ? { title: { contains: q as string, mode: "insensitive" } } : {},
minPrice ? { price: { gte: Number(minPrice) } } : {},
maxPrice ? { price: { lte: Number(maxPrice) } } : {},
category ? { category: { name: category as string } } : {},
],
},
});
res.json(products);
}Admin Dashboard Features
Key features for store management:
- Product CRUD operations
- Order management and tracking
- Inventory management
- Sales analytics and reports
- Customer management
Real-World Example: Floral Radiance
Lessons from building Floral Radiance:
- Real-time Updates: Used WebSockets for live inventory
- Responsive Design: Mobile-first approach essential
- Payment Reliability: Implement retry logic for payments
- Customer Support: Live chat integration improved conversions
- Analytics: Track user behavior and conversion funnels
Best Practices for E-Commerce
| Practice | Implementation |
|---|---|
| Data Validation | Server-side validation for all inputs |
| Security | PCI compliance, secure payment handling |
| Performance | CDN for assets, caching strategies |
| UX | Clear checkout flow, guest checkout option |
| Analytics | Track conversion funnels, user behavior |
Conclusion
Building e-commerce platforms requires balancing functionality, performance, security, and user experience. Next.js combined with modern backend services makes it possible to create world-class online stores.