A production-ready Next.js 15 e-commerce template powered by Contentstack
π― Built for Contentstack Explorer Accounts: This kickstart is specifically designed to work seamlessly with free Contentstack Explorer accounts, providing all the features you need to build stunning content-driven websites without any limitations.
Live Demo β’ Documentation β’ Getting Started
Veda: The Revival Collection is a fully-functional headless content template showcasing an upscale unisex jewelry line with four distinct product sets inspired by early 2000s pop culture. This kickstart demonstrates how to build a modern, production-ready Next.js application with Contentstack as the headless CMS.
β οΈ Important Note: This is a content template, not a complete e-commerce system. It includes product displays, categories, and rich content pages, but does not include shopping cart functionality, checkout processes, or payment integration. It's designed to showcase how to structure and display product content using Contentstack.
- β¨ Complete Content Structure: Products, product lines, categories, and dynamic pages (template only - no cart/checkout)
- π¨ Visual Builder Support: Full integration with Contentstack's Visual Builder
- π Live Preview: Real-time content updates with Contentstack Live Preview
- π― Type-Safe: Comprehensive TypeScript types for all content models
- β‘ Performance Optimized: Next.js App Router with streaming SSR and ISR
- π§© Component-Driven: Modular, reusable components with CSLP (Content Stack Live Preview) support
- π± Responsive Design: Mobile-first approach with Tailwind CSS 4.x
- πΌοΈ Image Optimization: Contentstack's built-in image delivery system for responsive images
- π Explorer-Ready: Optimized for Contentstack Explorer (free) accounts
This project follows a clean, scalable architecture designed for maintainability and developer experience:
kickstart-veda/
βββ app/ # Next.js 15 App Router
β βββ [[...slug]]/ # Catch-all dynamic pages
β βββ category/[category]/ # Category pages
β βββ products/
β β βββ [line]/[slug]/ # Individual product pages
β β βββ [line]/ # Product line pages
β βββ layout.tsx # Root layout with metadata
β βββ globals.css # Global styles
βββ components/
β βββ Atoms/ # Atomic components (Cta, Title, MediaItem)
β βββ Cards/ # Card components for listings
β βββ Pages/ # Page-level components
β β βββ Page.tsx # Generic page renderer
β β βββ Product.tsx # Product detail page
β β βββ ProductLine.tsx # Product line page
β β βββ Category.tsx # Category page
β β βββ Preview.tsx # Live preview wrapper
β βββ ComponentsRenderer.tsx # Dynamic component mapper
β βββ Hero.tsx # Hero banner component
β βββ List.tsx # List/Grid component
β βββ TwoColumn.tsx # Two-column layout
β βββ Media.tsx # Media component
β βββ RichText.tsx # Rich text renderer
β βββ MegaMenu.tsx # Navigation menu
β βββ Footer.tsx # Footer component
βββ lib/
βββ contentstack.ts # Contentstack SDK configuration
βββ types.ts # TypeScript type definitions
βββ pageUtils.ts # Page data fetching utilities
βββ filterSearch.ts # Search & filter utilities
- Node.js 20+ and npm
- A Contentstack account (Sign up for free)
- Basic knowledge of Next.js and React
The CLI helps you seed your stack with the content model and sample data:
npm install -g @contentstack/cli
# or use npx without global install
npx @contentstack/cliSet your region (Free Explorer accounts use the EU region):
# Check available regions
csdx config:get:region
# Set your region
csdx config:set:region EUπ Note: Despite using the EU region, Contentstack's CDN ensures lightning-fast API responses globally.
csdx auth:loginFind your Organization ID in your Contentstack dashboard under Org admin (e.g., blt481c598b0d8352d9), then run:
csdx cm:stacks:seed --repo "contentstack/kickstart-veda-seed" --org "<YOUR_ORG_ID>" -n "Veda: The Revival Collection"This command will:
- Create a new stack in your organization
- Set up all content types (Page, Product, Product Line, Category, Header)
- Import sample content and assets
- Configure taxonomies and relationships
- Navigate to
Settings > Tokensin your Contentstack dashboard - Click + Add token
- Name it (e.g., "Development Token")
- Select the
developmentscope - Enable Create preview token
- Save and copy both tokens
Create a .env.local file in the project root:
# Required: Your stack credentials
NEXT_PUBLIC_CONTENTSTACK_API_KEY=blt...
NEXT_PUBLIC_CONTENTSTACK_DELIVERY_TOKEN=cs...
NEXT_PUBLIC_CONTENTSTACK_PREVIEW_TOKEN=cs...
NEXT_PUBLIC_CONTENTSTACK_REGION=EU
NEXT_PUBLIC_CONTENTSTACK_ENVIRONMENT=development
# Enable Live Preview
NEXT_PUBLIC_CONTENTSTACK_PREVIEW=true
# Optional: Custom endpoints (usually not needed)
# NEXT_PUBLIC_CONTENTSTACK_CONTENT_DELIVERY=
# NEXT_PUBLIC_CONTENTSTACK_PREVIEW_HOST=
# NEXT_PUBLIC_CONTENTSTACK_CONTENT_APPLICATION=
# NEXT_PUBLIC_CONTENTSTACK_IMAGE_HOSTNAME=π‘ Tip: You can find all these values under
Settings > Tokens > [Your Token]
- Go to
Settings > Live Previewin your Contentstack dashboard - Click Enable
- Select the
developmentenvironment - Set the preview URL:
http://localhost:3000(or your deployment URL for production) - Save the configuration
npm install
npm run devYour site will be available at http://localhost:3000 π
- Open your Contentstack dashboard
- Navigate to
Entries > Page(or any content type) - Select an entry
- Click the Live Preview icon in the sidebar
- Edit content and see changes in real-time!
You can also use the Visual Builder to drag and drop components visually.
Contentstack Live Preview is a powerful feature that bridges your CMS and your application, enabling real-time content editing without page refreshes. Here's how it works:
-
SDK Integration: The
@contentstack/live-preview-utilspackage establishes a communication channel between the Contentstack UI and your application. -
CSLP (Content Stack Live Preview) Tags: Every editable field receives a unique
data-cslpattribute that identifies it to the Live Preview system.
// lib/contentstack.ts
export function initLivePreview() {
ContentstackLivePreview.init({
ssr: false,
enable: process.env.NEXT_PUBLIC_CONTENTSTACK_PREVIEW === "true",
mode: "builder", // Enables Visual Builder
stackSdk: stack.config as IStackSdk,
stackDetails: {
apiKey: process.env.NEXT_PUBLIC_CONTENTSTACK_API_KEY as string,
environment: process.env.NEXT_PUBLIC_CONTENTSTACK_ENVIRONMENT as string,
},
clientUrlParams: {
host:
process.env.NEXT_PUBLIC_CONTENTSTACK_CONTENT_APPLICATION ||
endpoints.application,
},
editButton: {
enable: true,
exclude: ["outsideLivePreviewPortal"],
},
});
}- Editable Tags: When fetching content, editable tags are automatically added in preview mode:
if (isPreview) {
contentstack.Utils.addEditableTags(entry, "page", true);
}- Real-time Updates: When you edit a field in Contentstack, the Live Preview system:
- Detects the change via the
data-cslpattribute - Fetches the updated content from the Preview API
- Updates only the changed field in your browser (no full page reload)
- Detects the change via the
The Visual Builder mode (mode: "builder") enables drag-and-drop functionality:
- Add Components: Click the "+" button to add new modular blocks
- Reorder Components: Drag components to rearrange them
- Delete Components: Remove unwanted sections
- Edit In-Place: Click any text or image to edit directly
All changes are reflected instantly in the preview pane while you work.
The ComponentsRenderer dynamically maps Contentstack components to React components:
// components/ComponentsRenderer.tsx
const componentMap = {
hero: HeroComponent,
list: ListComponent,
two_column: TwoColumnComponent,
media: MediaComponent,
rich_text: RichTextComponent,
} as const;
export const ComponentsRenderer: React.FC<ComponentsRendererProps> = ({
components,
cslp,
cslpWrapper,
}) => {
const mappedComponents = mapComponentsToKV(components);
const renderComponent = (component: any, index: number) => {
const Component = componentMap[component.name];
const element = <Component {...component.props} key={key} />;
// Wrap with CSLP attributes for Live Preview editing
return isPreview && cslp?.[`${cslpWrapper}__${index}`] ? (
<div {...cslp?.[`${cslpWrapper}__${index}`]} key={key}>
{element}
</div>
) : (
element
);
};
return <>{mappedComponents.map(renderComponent)}</>;
};This approach allows content editors to add, remove, and reorder components without code changes.
The SDK is configured with region-specific endpoints and Live Preview support:
// lib/contentstack.ts
const region = getRegionForString(process.env.NEXT_PUBLIC_CONTENTSTACK_REGION);
const endpoints = getContentstackEndpoints(region, true);
export const stack = contentstack.stack({
apiKey: process.env.NEXT_PUBLIC_CONTENTSTACK_API_KEY as string,
deliveryToken: process.env.NEXT_PUBLIC_CONTENTSTACK_DELIVERY_TOKEN as string,
environment: process.env.NEXT_PUBLIC_CONTENTSTACK_ENVIRONMENT as string,
region: region,
host: endpoints?.contentDelivery,
live_preview: {
enable: process.env.NEXT_PUBLIC_CONTENTSTACK_PREVIEW === "true",
preview_token: process.env.NEXT_PUBLIC_CONTENTSTACK_PREVIEW_TOKEN,
host: endpoints?.preview,
},
});All content types have TypeScript interfaces and cached fetch functions:
// lib/contentstack.ts
export async function getPage(url: string): Promise<Page> {
const result = await stack
.contentType("page")
.entry()
.addParams({ include_all: true, include_all_depth: 2 })
.query()
.where("url", QueryOperation.EQUALS, url)
.find<Page>();
if (result.entries) {
const entry = result.entries[0];
// Add editable tags for Live Preview
if (isPreview) {
contentstack.Utils.addEditableTags(entry, "page", true);
}
return entry;
}
throw new Error(`Page not found for url: ${url}`);
}
// Cached version for performance
export const getPageCached = cache(getPage);The pageUtils.ts file provides unified utilities for all content types:
// lib/pageUtils.ts
export function buildPath(
type: "page" | "category" | "product" | "productLine",
params: any
): string {
switch (type) {
case "page":
return params.slug ? `/${params.slug.join("/")}` : "/";
case "category":
return `/category/${params.category}`;
case "product":
return `/products/${params.line}/${params.slug}`;
case "productLine":
return `/products/${params.line}`;
}
}
export async function fetchPageData(params: { slug?: string[] }) {
const path = buildPath("page", params);
const header = await getHeaderCached();
const content = await getPageCached(path);
return {
content,
header,
path,
isPreview,
previewType: "page" as const,
};
}Components receive CSLP attributes via the $ prop for Live Preview integration:
// components/Hero.tsx
export default function Hero({
description,
design,
image,
title,
video,
ctas,
$, // CSLP attributes for live editing
}: HeroProps) {
return (
<div className="md:aspect-[1440/635] relative w-full overflow-hidden">
{image?.url && (
<MediaItem
{...($ && $.image)} // Attach CSLP to make image editable
src={image.url}
width={1440}
height={635}
alt={title || image.title || ""}
/>
)}
<article>
<Title
$={$ && $.title} // Attach CSLP to make title editable
text={title}
/>
<p {...($ && $.description)}>{description}</p>
</article>
</div>
);
}The [[...slug]] route handles all dynamic pages:
// app/[[...slug]]/page.tsx
export default async function SlugPage({ params }: SlugPageProps) {
const {
content: page,
header,
path,
isPreview,
previewType,
} = await fetchPageData(await params);
if (isPreview) {
return <Preview path={path} header={header} type={previewType} />;
}
return <Page page={page} header={header} />;
}
// Enable ISR with 30-minute revalidation
export const revalidate = 1800;
export const dynamic = "force-static";| Content Type | Purpose | Key Fields |
|---|---|---|
| Page | Generic pages (homepage, about, etc.) | url, title, description, components[] |
| Product | Individual jewelry items | title, url, price, description, media[], product_line[], category[] |
| Product Line | Collections (e.g., "Digital Dawn") | title, url, description, image, products[] |
| Category | Product categories (Earrings, Rings, etc.) | title, url, description, media, products[] |
| Header | Site navigation | logo, links[] |
Pages and PDPs use modular blocks for flexible layouts:
- Hero: Full-width banner with image/video, title, description, and CTAs
- List: Grid of cards (products, categories, or static cards)
- Two Column: Split layout with media, rich text, or lists on each side
- Media: Standalone image or video block
- Rich Text: WYSIWYG content with embedded assets
Products are organized using Contentstack's taxonomy feature:
- Product Line: Digital Dawn, Urban Armor, Charmed Revival, Elegant Rebellion
- Category: Earrings, Necklaces, Bracelets, Rings
This project uses Tailwind CSS 4.x with the new PostCSS plugin architecture:
// postcss.config.mjs
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};Global styles are defined in app/globals.css:
@import "tailwindcss";
:root {
--font-inter: "Inter", sans-serif;
}
/* Custom utilities for text shadow */
.text-shadow-sm {
text-shadow: 0 1px 2px rgb(0 0 0 / 0.5);
}Images are optimized using Contentstack's built-in image delivery system, which provides a powerful transformation API directly from your assets.
Contentstack automatically serves optimized images from your Digital Asset Management (DAM) system using URL parameters:
// Example: Contentstack image transformation
const imageUrl = `${asset.url}?width=800&height=600&format=webp&quality=80`;Contentstack supports various image transformations:
// Responsive image with multiple sizes
const srcset = [400, 800, 1200]
.map((width) => `${asset.url}?width=${width}&auto=webp ${width}w`)
.join(", ");- Automatic Format Selection: Serves WebP or AVIF based on browser support when using
auto=webp - Responsive Sizing: Generate multiple image sizes on-the-fly with the
widthparameter - Quality Control: Adjust image quality with the
qualityparameter (1-100) - Cropping & Fitting: Use
fit,crop, andfocal_pointfor precise control - CDN Distribution: All images served through Contentstack's global CDN
- No External Dependencies: No need for third-party services like Cloudinary
- Lazy Loading: Implemented with native browser
loading="lazy"attribute - Eager Loading: Priority images use
loading="eager"andfetchPriority="high"
// Crop to specific dimensions
`${asset.url}?width=800&height=600&fit=crop` // Maintain aspect ratio
`${asset.url}?width=800&fit=bounds` // Compress for performance
`${asset.url}?quality=80&auto=webp` // Smart crop with focal point
`${asset.url}?width=800&height=600&crop=focalpoint&fp-x=0.5&fp-y=0.5`;This approach keeps everything within the Contentstack ecosystem, perfect for Explorer accounts!
All sensitive credentials use the NEXT_PUBLIC_ prefix for client-side access while maintaining security through Contentstack's token scopes:
- Delivery Tokens: Read-only access to published content
- Preview Tokens: Read access to draft content (only enabled in preview mode)
- Sanitized rich text rendering with
isomorphic-dompurify - Type-safe content models prevent injection attacks
- Server-side data fetching prevents exposure of sensitive data
- ISR (Incremental Static Regeneration): Pages revalidate every 30 minutes
- React Cache: Prevents duplicate API calls during SSR
- Streaming SSR: Fast Time to First Byte (TTFB)
- Image Optimization: Lazy loading and responsive sizes
npm run dev # Start development server
npm run build # Build for production
npm run start # Start production server
npm run lint # Run ESLintThe updateLaunchConfig.mjs script automatically generates a launch.json file for Contentstack Launch deployments. This script runs before each build to optimize performance:
What it does:
- Connects to your Contentstack stack
- Fetches all URLs from your content (pages, products, categories, product lines)
- Generates a
launch.jsonfile with cache priming configuration - Ensures all pages are pre-built and cached during deployment
Why it matters:
- Improves first-visit performance for users
- Prevents cold-start delays on initial page requests
- Optimizes CDN distribution across edge locations
- Makes your site instantly fast on Contentstack Launch
// package.json
{
"scripts": {
"prebuild": "npm run update-launch-config"
}
}The script runs automatically during npm run build, but you can also run it manually:
node updateLaunchConfig.mjs- Start the dev server:
npm run dev - Open Contentstack dashboard
- Navigate to any entry
- Click Live Preview to see real-time updates
- Use Visual Builder to drag and drop components
| Package | Version | Purpose |
|---|---|---|
next |
15.5.4 | React framework with App Router |
react |
19.1.1 | UI library |
@contentstack/delivery-sdk |
4.10.0 | Content delivery API client |
@contentstack/live-preview-utils |
4.0.2 | Live Preview integration |
@timbenniks/contentstack-endpoints |
1.0.16 | Region endpoint resolver |
tailwindcss |
4.x | Utility-first CSS framework |
lucide-react |
0.544.0 | Icon library |
isomorphic-dompurify |
2.28.0 | HTML sanitization |
tailwind-merge |
3.3.1 | Tailwind class merging utility |
This kickstart is perfect for:
- ποΈ Product Catalogs: Display products, collections, and categories (front-end only, no transactions)
- π Marketing Websites: Dynamic landing pages with modular components
- π° Content-Heavy Sites: Blogs, news sites, or documentation
- π¨ Design Systems: Showcase component libraries
- π POCs & MVPs: Rapid prototyping with visual editing
- π Learning Projects: Understand headless CMS architecture with real-world examples
- π’ Agency Presentations: Demonstrate Contentstack capabilities to clients
This template does not include:
- β Shopping cart functionality
- β User authentication/accounts
- β Checkout process
- β Payment processing
- β Order management
- β Inventory tracking
To build a complete e-commerce solution, you would need to integrate services like:
- Shopify (headless commerce)
- Stripe (payments)
- Auth0 (authentication)
- Algolia (search)
This kickstart is specifically designed to work seamlessly with Contentstack Explorer (free) accounts. All features demonstrated here are available in the Explorer plan:
- β Big amount of API Calls: No real restrictions on content delivery, unless you hyper scale
- β Live Preview: Real-time content editing and preview
- β Visual Builder: Drag-and-drop page building
- β Content Types: All the content models used in this project
- β Modular Blocks: Build flexible page layouts
- β Taxonomies: Organize content with categories and tags
- β Assets & DAM: Store and optimize images
- β Multiple Environments: Development, staging, production
- β Webhooks: Trigger builds on content changes
- β Content Delivery API: Fast, global CDN delivery
- β Personalize: Create personalized experiences for different audiences
- β Brand Kit: Maintain brand consistency across all content
- β Developer Hub: Access to SDKs, APIs, and developer resources
- β Marketplace: Browse and install extensions and integrations
- β Automate: Workflow automation and content orchestration
- β Data & Insights: Analytics and content performance metrics
- β Launch: Free hosting tier with automatic deployments
- π Learning: Explore headless CMS concepts
- π Prototyping: Build MVPs without cost
- π¨βπ» Personal Projects: Side projects and portfolios
- π Client Demos: Showcase capabilities to potential clients
- π§ͺ Experimentation: Test new ideas and architectures
But for most kickstart projects, the Explorer account has everything you need!
This is a kickstart project maintained by Contentstack. For issues or feature requests, please:
- Check existing issues on GitHub
- Join our Discord community
- Submit a pull request with clear description
This project is licensed under the MIT License. See LICENSE for details.
- π Contentstack Documentation
- π¬ Discord Community
