├── .env.example ├── .eslintrc.js ├── .github ├── dependabot.yml └── workflows │ └── test.yml ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .vscode ├── launch.json └── settings.json ├── README.md ├── app ├── [page] │ ├── layout.tsx │ ├── opengraph-image.tsx │ └── page.tsx ├── api │ └── revalidate │ │ └── route.ts ├── error.tsx ├── favicon.ico ├── globals.css ├── layout.tsx ├── opengraph-image.tsx ├── page.tsx ├── product │ └── [handle] │ │ └── page.tsx ├── robots.ts ├── search │ ├── [collection] │ │ ├── opengraph-image.tsx │ │ └── page.tsx │ ├── layout.tsx │ ├── loading.tsx │ └── page.tsx └── sitemap.ts ├── components ├── carousel.tsx ├── cart │ ├── actions.ts │ ├── add-to-cart.tsx │ ├── close-cart.tsx │ ├── delete-item-button.tsx │ ├── edit-item-quantity-button.tsx │ ├── index.tsx │ ├── modal.tsx │ └── open-cart.tsx ├── grid │ ├── index.tsx │ ├── three-items.tsx │ └── tile.tsx ├── icons │ ├── arrow-left.tsx │ ├── close.tsx │ ├── logo.tsx │ └── medusa.tsx ├── label.tsx ├── layout │ ├── footer-menu.tsx │ ├── footer.tsx │ ├── navbar │ │ ├── index.tsx │ │ ├── mobile-menu.tsx │ │ └── search.tsx │ ├── product-grid-items.tsx │ └── search │ │ ├── collections.tsx │ │ └── filter │ │ ├── dropdown.tsx │ │ ├── index.tsx │ │ └── item.tsx ├── loading-dots.tsx ├── logo-square.tsx ├── opengraph-image.tsx ├── price.tsx ├── product │ ├── gallery.tsx │ ├── product-description.tsx │ └── variant-selector.tsx └── prose.tsx ├── fonts └── Inter-Bold.ttf ├── lib ├── constants.ts ├── medusa │ ├── helpers.ts │ ├── index.ts │ └── types.ts ├── type-guards.ts └── utils.ts ├── license.md ├── next.config.js ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── prettier.config.js ├── tailwind.config.js ├── tsconfig.json └── yarn.lock /.env.example: -------------------------------------------------------------------------------- 1 | TWITTER_CREATOR="@medusajs" 2 | TWITTER_SITE="https://medusajs.com/" 3 | SITE_NAME="Medusa Store" 4 | NEXT_PUBLIC_MEDUSA_BACKEND_API="http://localhost:9000" 5 | NEXT_PUBLIC_VERCEL_URL="http://localhost:3000" 6 | MEDUSA_API_KEY="" 7 | MEDUSA_REVALIDATION_SECRET="supersecret123" -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['next', 'prettier'], 3 | plugins: ['unicorn'], 4 | rules: { 5 | 'no-unused-vars': [ 6 | 'error', 7 | { 8 | args: 'after-used', 9 | caughtErrors: 'none', 10 | ignoreRestSiblings: true, 11 | vars: 'all' 12 | } 13 | ], 14 | 'prefer-const': 'error', 15 | 'react-hooks/exhaustive-deps': 'error', 16 | 'unicorn/filename-case': [ 17 | 'error', 18 | { 19 | case: 'kebabCase' 20 | } 21 | ] 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'github-actions' 4 | directory: '/' 5 | schedule: 6 | interval: 'weekly' 7 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | on: pull_request 3 | jobs: 4 | test: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Cancel running workflows 8 | uses: styfle/cancel-workflow-action@0.11.0 9 | with: 10 | access_token: ${{ github.token }} 11 | - name: Checkout repo 12 | uses: actions/checkout@v3 13 | - name: Set node version 14 | uses: actions/setup-node@v3 15 | with: 16 | node-version-file: '.nvmrc' 17 | - name: Set pnpm version 18 | uses: pnpm/action-setup@v2 19 | with: 20 | run_install: false 21 | version: 7 22 | - name: Cache node_modules 23 | id: node-modules-cache 24 | uses: actions/cache@v3 25 | with: 26 | path: '**/node_modules' 27 | key: node-modules-cache-${{ hashFiles('**/pnpm-lock.yaml') }} 28 | - name: Install dependencies 29 | if: steps.node-modules-cache.outputs.cache-hit != 'true' 30 | run: pnpm install 31 | - name: Run tests 32 | run: pnpm test 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | .playwright 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | .pnpm-debug.log* 28 | 29 | # local env files 30 | .env* 31 | !.env.example 32 | 33 | # vercel 34 | .vercel 35 | 36 | # typescript 37 | *.tsbuildinfo 38 | next-env.d.ts 39 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 18 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .vercel 2 | .next 3 | pnpm-lock.yaml 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Next.js: debug server-side", 6 | "type": "node-terminal", 7 | "request": "launch", 8 | "command": "pnpm dev" 9 | }, 10 | { 11 | "name": "Next.js: debug client-side", 12 | "type": "chrome", 13 | "request": "launch", 14 | "url": "http://localhost:3000" 15 | }, 16 | { 17 | "name": "Next.js: debug full stack", 18 | "type": "node-terminal", 19 | "request": "launch", 20 | "command": "pnpm dev", 21 | "serverReadyAction": { 22 | "pattern": "started server on .+, url: (https?://.+)", 23 | "uriFormat": "%s", 24 | "action": "debugWithChrome" 25 | } 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "typescript.enablePromptUseWorkspaceTsdk": true, 4 | "editor.codeActionsOnSave": { 5 | "source.fixAll": true, 6 | "source.organizeImports": true, 7 | "source.sortMembers": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fmedusajs%2Fvercel-commerce&env=MEDUSA_API_KEY,SITE_NAME,NEXT_PUBLIC_MEDUSA_BACKEND_API,NEXT_PUBLIC_VERCEL_URL,TWITTER_SITE,TWITTER_CREATOR&project-name=medusa-nextjs-commerce&repository-name=medusa-nextjs-commerce&redirect-url=https%3A%2F%2Fdocs.medusajs.com%2F%3Futm_source%3Dvercel%26utm_medium%3Ddeploy%2Bbutton%26utm_campaign%3Dcommerce&demo-title=Next.js%20Commerce%20by%20Medusa&demo-description=A%20Next.js%2013%20and%20ecommerce%20template%2C%20built%20with%20Medusa.&demo-url=https%3A%2F%2Fmedusa-nextjs-commerce.vercel.app%2F&demo-image=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F62591822%3Fs%3D200%26v%3D4) 2 | 3 | # Next.js Commerce x Medusa 4 | 5 | > Note: Looking for Next.js Commerce v1? View the [code](https://github.com/vercel/commerce/tree/v1), [demo](https://commerce-v1.vercel.store), and [release notes](https://github.com/vercel/commerce/releases/tag/v1) 6 | 7 | A Next.js 13 and App Router-ready ecommerce template, built with [Medusa](https://github.com/medusajs/medusa), featuring: 8 | 9 | - Next.js App Router 10 | - Optimized for SEO using Next.js's Metadata 11 | - React Server Components (RSCs) and Suspense 12 | - Server Actions for mutations 13 | - Edge Runtime 14 | - New fetching and caching paradigms 15 | - Dynamic OG images 16 | - Styling with Tailwind CSS 17 | - Automatic light/dark mode based on system settings 18 | 19 | ## What is Medusa? 20 | 21 | [Medusa](https://medusajs.com/) is a set of commerce modules and tools that allow you to build rich, reliable, and performant commerce applications without reinventing core commerce logic. The modules can be customized and used to build advanced ecommerce stores, marketplaces, or any system that needs foundational commerce primitives. All modules are open-source and freely available on NPM. 22 | 23 | Learn more about [Medusa’s architecture](https://docs.medusajs.com/development/fundamentals/architecture-overview) and [commerce modules](https://docs.medusajs.com/modules/overview) in Medusa's documentation. 24 | 25 | ## Getting started 26 | 27 | > Please refer to the [documentation](https://docs.medusajs.com/development/backend/install#prerequisites) to learn about required tools for the Medusa Backend. 28 | 29 | 1\. Run `create-medusa-app` with the `nextjs-commerce` starter: 30 | 31 | ```bash 32 | npx create-medusa-app@nextjs-commerce 33 | ``` 34 | 35 | This will create a new main folder with two subfolders for Medusa and Next.js Commerce respectively. 36 | 37 | 2\. Create a Postgres database named `vercel-commerce` and make sure the Postgres server is running locally. 38 | 39 | 3\. Inside your newly created `nextjs-commerce` project, change to the `medusa` folder and seed the database: 40 | 41 | ```bash 42 | cd nextjs-commerce/medusa 43 | yarn seed 44 | ``` 45 | 46 | This will provide you with some demo products and the necessary product categories to fill out the homepage. 47 | 48 | ## Running Medusa 49 | 50 | From the `medusa` subfolder, run: 51 | 52 | ```bash 53 | yarn start 54 | ``` 55 | 56 | Your Medusa server should now be running on [localhost:9000](http://localhost:9000/). 57 | 58 | ## Running Next.js Commerce 59 | 60 | 1\. You will need to use the environment variables [defined in `.env.example`](.env.example) to run Next.js Commerce. Copy the contents of .env.example to a .env file in the root of your Next.js Commerce project, and make sure the NEXT_PUBLIC_MEDUSA_BACKEND_API environment variable points to your Medusa backend domain (default: http://localhost:9000). 61 | 62 | > Note: You should not commit your `.env` file or it will expose secrets. 63 | 64 | 2\. From the `nextjs-commerce` subfolder, run: 65 | 66 | ```bash 67 | yarn dev 68 | ``` 69 | 70 | Your app should now be running on [localhost:3000](http://localhost:3000/). 71 | -------------------------------------------------------------------------------- /app/[page]/layout.tsx: -------------------------------------------------------------------------------- 1 | import Footer from 'components/layout/footer'; 2 | import { Suspense } from 'react'; 3 | 4 | export default function Layout({ children }: { children: React.ReactNode }) { 5 | return ( 6 | 7 |
8 |
9 | {children} 10 |
11 |
12 |