Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
25ddc5e
Update dependencies. (#1314)
leerob Mar 26, 2024
610b0e8
Remove stray revalidate
leerob Mar 31, 2024
887d437
Prepare for using PPR (#1236)
leerob Apr 18, 2024
a5de917
fix: disabled button classes when selectedVariantId is defined are no…
elberthcorniell May 4, 2024
42d5d8e
Adds Ecwid by Lightspeed to providers section (#1304)
meteor-ec May 7, 2024
7fd9ad8
Update README.md (#1339)
JustinApt May 26, 2024
7c1b34a
Remove any type and make removeEdgesAndNodes generic (#1353)
harrybuisman Jul 14, 2024
ec21369
Update dependencies. (#1361)
leerob Jul 24, 2024
d7a4f3d
feat(design): Show carousel above the fold on desktop (#1363)
vvo Jul 25, 2024
0ebf071
Optimistic cart (#1364)
leerob Jul 25, 2024
cea56f6
Fix bugs with optimistic.
leerob Jul 25, 2024
dd7449f
Make deleting optimistic too.
leerob Jul 25, 2024
9a4c995
Make image, variant, and cart updates faster with `useOptimistic` (#1…
leerob Jul 29, 2024
37cb5e3
Small cleanup.
leerob Jul 29, 2024
94b85fc
Update README
leerob Jul 29, 2024
84224f8
Fix bug with disabled state
leerob Jul 29, 2024
556aa77
README: added React Bricks integration (#1367)
matteofrana Aug 7, 2024
694c5c1
Move to `next/form` (#1369)
leerob Aug 13, 2024
64ca2ac
Update to 15 RC 2
leerob Oct 16, 2024
815bea2
chore: update readme (#1381)
bnzone Oct 16, 2024
cb99695
Correct default cart tax currency (#1260)
matthew-petrie Oct 16, 2024
b7e9e1c
Refactor <Prose> component (#1352)
chogyejin Oct 16, 2024
ce004c0
Update tailwind.config.ts (#1388)
omkarkulkarni2704 Oct 18, 2024
8d4cc9a
fixing response status code for no secret or wrong secret (#1397)
newlomar Oct 27, 2024
cf413a5
Update gallery.tsx (#1403)
dharmveer97 Nov 21, 2024
3a26bae
Add Fourthwall as a commerce provider (#1394)
jurrchen Nov 21, 2024
386392b
feat: added geins as a commerce provider (#1414)
arvidsson-geins Nov 28, 2024
88762ba
Update deps
leerob Dec 6, 2024
6759421
Adds Prodigy Commerce as a commerce provider. (#1415)
polykoi Jan 21, 2025
7f8f9ff
use cache
leerob Feb 9, 2025
6946bf7
Fix production base url (#1429)
johnstringerm Feb 10, 2025
63725d8
Update deps
leerob Feb 21, 2025
9f4fdbb
Merge branch 'main' of github.com:vercel/commerce
leerob Feb 21, 2025
28f9a64
Update Wix fork repository (#1439)
netanelgilad Feb 24, 2025
ef2883a
Update deps.
leerob Mar 19, 2025
fa13069
Merge branch 'main' of github.com:vercel/commerce
leerob Mar 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
COMPANY_NAME="Vercel Inc."
TWITTER_CREATOR="@vercel"
TWITTER_SITE="https://nextjs.org/commerce"
SITE_NAME="Next.js Commerce"
SHOPIFY_REVALIDATION_SECRET=""
SHOPIFY_STOREFRONT_ACCESS_TOKEN=""
Expand Down
23 changes: 0 additions & 23 deletions .eslintrc.js

This file was deleted.

6 changes: 0 additions & 6 deletions .github/dependabot.yml

This file was deleted.

35 changes: 0 additions & 35 deletions .github/workflows/test.yml

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
.env*.local
1 change: 0 additions & 1 deletion .nvmrc

This file was deleted.

3 changes: 0 additions & 3 deletions .prettierignore

This file was deleted.

6 changes: 3 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.organizeImports": true,
"source.sortMembers": true
"source.fixAll": "explicit",
"source.organizeImports": "explicit",
"source.sortMembers": "explicit"
}
}
27 changes: 13 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fcommerce&project-name=commerce&repo-name=commerce&demo-title=Next.js%20Commerce&demo-url=https%3A%2F%2Fdemo.vercel.store&demo-image=https%3A%2F%2Fbigcommerce-demo-asset-ksvtgfvnd.vercel.app%2Fbigcommerce.png&env=COMPANY_NAME,SHOPIFY_REVALIDATION_SECRET,SHOPIFY_STORE_DOMAIN,SHOPIFY_STOREFRONT_ACCESS_TOKEN,SITE_NAME,TWITTER_CREATOR,TWITTER_SITE)
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fcommerce&project-name=commerce&repo-name=commerce&demo-title=Next.js%20Commerce&demo-url=https%3A%2F%2Fdemo.vercel.store&demo-image=https%3A%2F%2Fbigcommerce-demo-asset-ksvtgfvnd.vercel.app%2Fbigcommerce.png&env=COMPANY_NAME,SHOPIFY_REVALIDATION_SECRET,SHOPIFY_STORE_DOMAIN,SHOPIFY_STOREFRONT_ACCESS_TOKEN,SITE_NAME)

# Next.js Commerce

A Next.js 14 and App Router-ready ecommerce template featuring:
A high-performance, server-rendered Next.js App Router ecommerce application.

- Next.js App Router
- Optimized for SEO using Next.js's Metadata
- React Server Components (RSCs) and Suspense
- Server Actions for mutations
- Edge Runtime
- New fetching and caching paradigms
- Dynamic OG images
- Styling with Tailwind CSS
- Checkout and payments with Shopify
- Automatic light/dark mode based on system settings
This template uses React Server Components, Server Actions, `Suspense`, `useOptimistic`, and more.

<h3 id="v1-note"></h3>

Expand All @@ -27,12 +18,16 @@ Vercel is happy to partner and work with any commerce provider to help them get

- Shopify (this repository)
- [BigCommerce](https://github.com/bigcommerce/nextjs-commerce) ([Demo](https://next-commerce-v2.vercel.app/))
- [Ecwid by Lightspeed](https://github.com/Ecwid/ecwid-nextjs-commerce/) ([Demo](https://ecwid-nextjs-commerce.vercel.app/))
- [Geins](https://github.com/geins-io/vercel-nextjs-commerce) ([Demo](https://geins-nextjs-commerce-starter.vercel.app/))
- [Medusa](https://github.com/medusajs/vercel-commerce) ([Demo](https://medusa-nextjs-commerce.vercel.app/))
- [Prodigy Commerce](https://github.com/prodigycommerce/nextjs-commerce) ([Demo](https://prodigy-nextjs-commerce.vercel.app/))
- [Saleor](https://github.com/saleor/nextjs-commerce) ([Demo](https://saleor-commerce.vercel.app/))
- [Shopware](https://github.com/shopwareLabs/vercel-commerce) ([Demo](https://shopware-vercel-commerce-react.vercel.app/))
- [Swell](https://github.com/swellstores/verswell-commerce) ([Demo](https://verswell-commerce.vercel.app/))
- [Umbraco](https://github.com/umbraco/Umbraco.VercelCommerce.Demo) ([Demo](https://vercel-commerce-demo.umbraco.com/))
- [Wix](https://github.com/wix/nextjs-commerce) ([Demo](https://wix-nextjs-commerce.vercel.app/))
- [Wix](https://github.com/wix/headless-templates/tree/main/nextjs/commerce) ([Demo](https://wix-nextjs-commerce.vercel.app/))
- [Fourthwall](https://github.com/FourthwallHQ/vercel-commerce) ([Demo](https://vercel-storefront.fourthwall.app/))

> Note: Providers, if you are looking to use similar products for your demo, you can [download these assets](https://drive.google.com/file/d/1q_bKerjrwZgHwCw0ovfUMW6He9VtepO_/view?usp=sharing).

Expand All @@ -41,9 +36,13 @@ Vercel is happy to partner and work with any commerce provider to help them get
Integrations enable upgraded or additional functionality for Next.js Commerce

- [Orama](https://github.com/oramasearch/nextjs-commerce) ([Demo](https://vercel-commerce.oramasearch.com/))

- Upgrades search to include typeahead with dynamic re-rendering, vector-based similarity search, and JS-based configuration.
- Search runs entirely in the browser for smaller catalogs or on a CDN for larger.

- [React Bricks](https://github.com/ReactBricks/nextjs-commerce-rb) ([Demo](https://nextjs-commerce.reactbricks.com/))
- Edit pages, product details, and footer content visually using [React Bricks](https://www.reactbricks.com) visual headless CMS.

## Running locally

You will need to use the environment variables [defined in `.env.example`](.env.example) to run Next.js Commerce. It's recommended you use [Vercel Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables) for this, but a `.env` file is all that is necessary.
Expand Down Expand Up @@ -73,4 +72,4 @@ Your app should now be running on [localhost:3000](http://localhost:3000/).

## Vercel, Next.js Commerce, and Shopify Integration Guide

You can use this comprehensive [integration guide](http://vercel.com/docs/integrations/shopify) with step-by-step instructions on how to configure Shopify as a headless CMS using Next.js Commerce as your headless Shopify storefront on Vercel.
You can use this comprehensive [integration guide](https://vercel.com/docs/integrations/ecommerce/shopify) with step-by-step instructions on how to configure Shopify as a headless CMS using Next.js Commerce as your headless Shopify storefront on Vercel.
9 changes: 3 additions & 6 deletions app/[page]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import Footer from 'components/layout/footer';
import { Suspense } from 'react';

export default function Layout({ children }: { children: React.ReactNode }) {
return (
<Suspense>
<>
<div className="w-full">
<div className="mx-8 max-w-2xl py-20 sm:mx-auto">
<Suspense>{children}</Suspense>
</div>
<div className="mx-8 max-w-2xl py-20 sm:mx-auto">{children}</div>
</div>
<Footer />
</Suspense>
</>
);
}
2 changes: 0 additions & 2 deletions app/[page]/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import OpengraphImage from 'components/opengraph-image';
import { getPage } from 'lib/shopify';

export const runtime = 'edge';

export default async function Image({ params }: { params: { page: string } }) {
const page = await getPage(params.page);
const title = page.seo?.title || page.title;
Expand Down
16 changes: 6 additions & 10 deletions app/[page]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@ import Prose from 'components/prose';
import { getPage } from 'lib/shopify';
import { notFound } from 'next/navigation';

export const runtime = 'edge';

export const revalidate = 43200; // 12 hours in seconds

export async function generateMetadata({
params
}: {
params: { page: string };
export async function generateMetadata(props: {
params: Promise<{ page: string }>;
}): Promise<Metadata> {
const params = await props.params;
const page = await getPage(params.page);

if (!page) return notFound();
Expand All @@ -28,15 +23,16 @@ export async function generateMetadata({
};
}

export default async function Page({ params }: { params: { page: string } }) {
export default async function Page(props: { params: Promise<{ page: string }> }) {
const params = await props.params;
const page = await getPage(params.page);

if (!page) return notFound();

return (
<>
<h1 className="mb-8 text-5xl font-bold">{page.title}</h1>
<Prose className="mb-8" html={page.body as string} />
<Prose className="mb-8" html={page.body} />
<p className="text-sm italic">
{`This document was last updated on ${new Intl.DateTimeFormat(undefined, {
year: 'numeric',
Expand Down
2 changes: 0 additions & 2 deletions app/api/revalidate/route.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { revalidate } from 'lib/shopify';
import { NextRequest, NextResponse } from 'next/server';

export const runtime = 'edge';

export async function POST(req: NextRequest): Promise<NextResponse> {
return revalidate(req);
}
2 changes: 1 addition & 1 deletion app/error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

export default function Error({ reset }: { reset: () => void }) {
return (
<div className="mx-auto my-4 flex max-w-xl flex-col rounded-lg border border-neutral-200 bg-white p-8 dark:border-neutral-800 dark:bg-black md:p-12">
<div className="mx-auto my-4 flex max-w-xl flex-col rounded-lg border border-neutral-200 bg-white p-8 md:p-12 dark:border-neutral-800 dark:bg-black">
<h2 className="text-xl font-bold">Oh no!</h2>
<p className="my-2">
There was an issue with our storefront. This could be a temporary issue, please try your
Expand Down
19 changes: 15 additions & 4 deletions app/globals.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import 'tailwindcss';

@plugin "@tailwindcss/container-queries";
@plugin "@tailwindcss/typography";

@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}

@media (prefers-color-scheme: dark) {
html {
Expand All @@ -17,5 +28,5 @@
a,
input,
button {
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-400 focus-visible:ring-offset-2 focus-visible:ring-offset-neutral-50 dark:focus-visible:ring-neutral-600 dark:focus-visible:ring-offset-neutral-900;
@apply focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-neutral-400 focus-visible:ring-offset-2 focus-visible:ring-offset-neutral-50 dark:focus-visible:ring-neutral-600 dark:focus-visible:ring-offset-neutral-900;
}
50 changes: 26 additions & 24 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import Navbar from 'components/layout/navbar';
import { GeistSans } from 'geist/font';
import { ensureStartsWith } from 'lib/utils';
import { ReactNode, Suspense } from 'react';
import { CartProvider } from 'components/cart/cart-context';
import { Navbar } from 'components/layout/navbar';
import { WelcomeToast } from 'components/welcome-toast';
import { GeistSans } from 'geist/font/sans';
import { getCart } from 'lib/shopify';
import { ReactNode } from 'react';
import { Toaster } from 'sonner';
import './globals.css';
import { baseUrl } from 'lib/utils';

const { TWITTER_CREATOR, TWITTER_SITE, SITE_NAME } = process.env;
const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL
? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`
: 'http://localhost:3000';
const twitterCreator = TWITTER_CREATOR ? ensureStartsWith(TWITTER_CREATOR, '@') : undefined;
const twitterSite = TWITTER_SITE ? ensureStartsWith(TWITTER_SITE, 'https://') : undefined;
const { SITE_NAME } = process.env;

export const metadata = {
metadataBase: new URL(baseUrl),
Expand All @@ -20,25 +19,28 @@ export const metadata = {
robots: {
follow: true,
index: true
},
...(twitterCreator &&
twitterSite && {
twitter: {
card: 'summary_large_image',
creator: twitterCreator,
site: twitterSite
}
})
}
};

export default async function RootLayout({ children }: { children: ReactNode }) {
export default async function RootLayout({
children
}: {
children: ReactNode;
}) {
// Don't await the fetch, pass the Promise to the context provider
const cart = getCart();

return (
<html lang="en" className={GeistSans.variable}>
<body className="bg-neutral-50 text-black selection:bg-teal-300 dark:bg-neutral-900 dark:text-white dark:selection:bg-pink-500 dark:selection:text-white">
<Navbar />
<Suspense>
<main>{children}</main>
</Suspense>
<CartProvider cartPromise={cart}>
<Navbar />
<main>
{children}
<Toaster closeButton />
<WelcomeToast />
</main>
</CartProvider>
</body>
</html>
);
Expand Down
2 changes: 0 additions & 2 deletions app/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import OpengraphImage from 'components/opengraph-image';

export const runtime = 'edge';

export default async function Image() {
return await OpengraphImage();
}
16 changes: 5 additions & 11 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
import { Carousel } from 'components/carousel';
import { ThreeItemGrid } from 'components/grid/three-items';
import Footer from 'components/layout/footer';
import { Suspense } from 'react';

export const runtime = 'edge';

export const metadata = {
description: 'High-performance ecommerce store built with Next.js, Vercel, and Shopify.',
description:
'High-performance ecommerce store built with Next.js, Vercel, and Shopify.',
openGraph: {
type: 'website'
}
};

export default async function HomePage() {
export default function HomePage() {
return (
<>
<ThreeItemGrid />
<Suspense>
<Carousel />
<Suspense>
<Footer />
</Suspense>
</Suspense>
<Carousel />
<Footer />
</>
);
}
Loading