Convert Figma logo to code with AI

medusajs logonextjs-starter-medusa

A performant frontend ecommerce starter template with Next.js 14 and Medusa.

1,668
462
1,668
73

Top Related Projects

11,294

Next.js Commerce

Saleor Storefront built with React 18, Next.js 14, App Router, TypeScript, GraphQL, and Tailwind CSS.

Hydrogen lets you build faster headless storefronts in less time, on Shopify.

Quick Overview

The medusajs/nextjs-starter-medusa repository is a starter template for building e-commerce applications using Medusa, an open-source headless commerce engine, and Next.js, a popular React framework. This project provides a foundation for creating custom, high-performance online stores with a modern tech stack.

Pros

  • Seamless integration of Medusa's powerful e-commerce features with Next.js's performance and developer experience
  • Pre-configured setup for rapid development of custom online stores
  • Built-in responsive design and customizable components for easy UI modifications
  • Supports both server-side rendering (SSR) and static site generation (SSG) for optimal performance

Cons

  • Requires familiarity with both Medusa and Next.js ecosystems
  • Limited out-of-the-box design customization options compared to traditional e-commerce platforms
  • May have a steeper learning curve for developers new to headless commerce architectures
  • Potential challenges in integrating with certain third-party services not natively supported by Medusa

Code Examples

  1. Fetching products using Medusa's API:
import { medusaClient } from "@lib/config"

const { products } = await medusaClient.products.list()
  1. Creating a custom checkout flow:
import { useCart } from "medusa-react"

const { cart, createPaymentSessions } = useCart()

const handleCheckout = async () => {
  await createPaymentSessions()
  // Redirect to payment page
}
  1. Implementing a product search feature:
import { useState } from "react"
import { medusaClient } from "@lib/config"

const ProductSearch = () => {
  const [searchResults, setSearchResults] = useState([])

  const handleSearch = async (query) => {
    const { products } = await medusaClient.products.list({ q: query })
    setSearchResults(products)
  }

  // Render search results
}

Getting Started

To get started with the medusajs/nextjs-starter-medusa project:

  1. Clone the repository:

    git clone https://github.com/medusajs/nextjs-starter-medusa.git
    
  2. Install dependencies:

    cd nextjs-starter-medusa
    npm install
    
  3. Set up environment variables:

    cp .env.template .env.local
    

    Edit .env.local with your Medusa backend URL.

  4. Run the development server:

    npm run dev
    
  5. Open http://localhost:3000 in your browser to see the starter template in action.

Competitor Comparisons

11,294

Next.js Commerce

Pros of Commerce

  • More comprehensive e-commerce features, including cart, checkout, and product management
  • Better integration with Vercel's ecosystem and deployment platform
  • Larger community and more frequent updates

Cons of Commerce

  • Steeper learning curve due to more complex architecture
  • Less flexibility for customization compared to Medusa's modular approach
  • Potentially overkill for simpler e-commerce projects

Code Comparison

Commerce:

export const getStaticProps: GetStaticProps = async () => {
  const config = getConfig()
  const products = await getAllProducts(config)
  return {
    props: { products },
    revalidate: 60,
  }
}

Nextjs-starter-medusa:

export const getStaticProps = async () => {
  const products = await medusaClient.products.list()
  return {
    props: { products },
  }
}

The Commerce example showcases a more complex setup with configuration and revalidation, while Nextjs-starter-medusa offers a simpler approach using the Medusa client directly.

Both repositories provide solid foundations for building e-commerce applications with Next.js. Commerce offers a more feature-rich solution with tighter Vercel integration, while Nextjs-starter-medusa provides a simpler starting point with greater flexibility for customization. The choice between them depends on project requirements and developer preferences.

Saleor Storefront built with React 18, Next.js 14, App Router, TypeScript, GraphQL, and Tailwind CSS.

Pros of Storefront

  • More comprehensive e-commerce features out-of-the-box
  • Better internationalization support
  • Stronger focus on PWA capabilities

Cons of Storefront

  • Steeper learning curve due to complex architecture
  • Less flexibility for customization compared to Nextjs-starter-medusa
  • Potentially slower performance for smaller-scale projects

Code Comparison

Storefront (React with Apollo Client):

const ProductList = () => {
  const { loading, error, data } = useQuery(GET_PRODUCTS);
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;
  return data.products.map(({ id, name, price }) => (
    <div key={id}>{name} - {price}</div>
  ));
};

Nextjs-starter-medusa (Next.js with REST API):

export async function getServerSideProps() {
  const products = await medusaClient.products.list();
  return { props: { products } };
}

const ProductList = ({ products }) => {
  return products.map(({ id, title, variant }) => (
    <div key={id}>{title} - {variant.prices[0].amount}</div>
  ));
};

This comparison highlights the different approaches to data fetching and rendering between the two starters. Storefront uses GraphQL with Apollo Client, while Nextjs-starter-medusa utilizes Next.js server-side rendering with a REST API.

Hydrogen lets you build faster headless storefronts in less time, on Shopify.

Pros of Hydrogen

  • Seamless integration with Shopify's ecosystem and features
  • Built-in performance optimizations for e-commerce
  • Extensive documentation and community support

Cons of Hydrogen

  • Limited flexibility outside of Shopify's ecosystem
  • Potential vendor lock-in
  • Steeper learning curve for developers new to Shopify

Code Comparison

Hydrogen (React Server Components):

export default function Product({ params }) {
  const { handle } = params;
  const { product } = useShopQuery({
    query: PRODUCT_QUERY,
    variables: { handle },
  });

  return <ProductDetails product={product} />;
}

Nextjs-starter-medusa (Next.js):

export async function getStaticProps({ params }) {
  const { product } = await medusaClient.products.retrieve(params.id);
  return { props: { product } };
}

export default function Product({ product }) {
  return <ProductDetails product={product} />;
}

Both repositories offer starter templates for e-commerce applications, but they cater to different ecosystems. Hydrogen is tightly integrated with Shopify, providing a streamlined development experience for Shopify stores. It leverages React Server Components for improved performance.

Nextjs-starter-medusa, on the other hand, offers more flexibility and is not tied to a specific e-commerce platform. It uses Next.js, which provides a familiar development experience for React developers. The code comparison shows how both handle product retrieval, with Hydrogen using a custom hook and Nextjs-starter-medusa utilizing Next.js's data fetching methods.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Medusa logo

Medusa Next.js Starter Template

Combine Medusa's modules for your commerce backend with the newest Next.js 14 features for a performant storefront.

PRs welcome! Discord Chat Follow @medusajs

Prerequisites

To use the Next.js Starter Template, you should have a Medusa server running locally on port 9000. For a quick setup, run:

npx create-medusa-app@latest

Check out create-medusa-app docs for more details and troubleshooting.

Overview

The Medusa Next.js Starter is built with:

Features include:

  • Full ecommerce support:
    • Product Detail Page
    • Product Overview Page
    • Search with Algolia / MeiliSearch
    • Product Collections
    • Cart
    • Checkout with PayPal and Stripe
    • User Accounts
    • Order Details
  • Full Next.js 14 support:
    • App Router
    • Next fetching/caching
    • Server Components
    • Server Actions
    • Streaming
    • Static Pre-Rendering

Quickstart

Setting up the environment variables

Navigate into your projects directory and get your environment variables ready:

cd nextjs-starter-medusa/
mv .env.template .env.local

Install dependencies

Use Yarn to install all dependencies.

yarn

Start developing

You are now ready to start up your project.

yarn dev

Open the code and start customizing

Your site is now running at http://localhost:8000!

Payment integrations

By default this starter supports the following payment integrations

To enable the integrations you need to add the following to your .env.local file:

NEXT_PUBLIC_STRIPE_KEY=<your-stripe-public-key>
NEXT_PUBLIC_PAYPAL_CLIENT_ID=<your-paypal-client-id>

You will also need to setup the integrations in your Medusa server. See the Medusa documentation for more information on how to configure Stripe and PayPal in your Medusa project.

Search integration

This starter is configured to support using the medusa-search-meilisearch plugin out of the box. To enable search you will need to enable the feature flag in ./store.config.json, which you do by changing the config to this:

{
  "features": {
    // other features...
    "search": true
  }
}

Before you can search you will need to install the plugin in your Medusa server, for a written guide on how to do this – see our documentation.

The search components in this starter are developed with Algolia's react-instant-search-hooks-web library which should make it possible for you to seemlesly change your search provider to Algolia instead of MeiliSearch.

To do this you will need to add algoliasearch to the project, by running

yarn add algoliasearch

After this you will need to switch the current MeiliSearch SearchClient out with a Alogolia client. To do this update @lib/search-client.

import algoliasearch from "algoliasearch/lite"

const appId = process.env.NEXT_PUBLIC_SEARCH_APP_ID || "test_app_id" // You should add this to your environment variables

const apiKey = process.env.NEXT_PUBLIC_SEARCH_API_KEY || "test_key"

export const searchClient = algoliasearch(appId, apiKey)

export const SEARCH_INDEX_NAME =
  process.env.NEXT_PUBLIC_INDEX_NAME || "products"

Then, in src/app/(main)/search/actions.ts, remove the MeiliSearch code (line 10-16) and uncomment the Algolia code.

"use server"

import { searchClient, SEARCH_INDEX_NAME } from "@lib/search-client"

/**
 * Uses MeiliSearch or Algolia to search for a query
 * @param {string} query - search query
 */
export async function search(query: string) {
  const index = searchClient.initIndex(SEARCH_INDEX_NAME)
  const { hits } = await index.search(query)

  return hits
}

After this you will need to set up Algolia with your Medusa server, and then you should be good to go. For a more thorough walkthrough of using Algolia with Medusa – see our documentation, and the documentation for using react-instantsearch-hooks-web.

App structure

For the new version, the main folder structure remains unchanged. The contents have changed quite a bit though.

.
└── src
    ├── app
    ├── lib
    ├── modules
    ├── styles
    ├── types
    └── middleware.ts

/app directory

The app folder contains all Next.js App Router pages and layouts, and takes care of the routing.

.
└── [countryCode]
    ├── (checkout)
        └── checkout
    └── (main)
        ├── account
        │   ├── addresses
        │   └── orders
        │       └── details
        │           └── [id]
        ├── cart
        ├── categories
        │   └── [...category]
        ├── collections
        │   └── [handle]
        ├── order
        │   └── confirmed
        │       └── [id]
        ├── products
        │   └── [handle]
        ├── results
        │   └── [query]
        ├── search
        └── store

The app router folder structure represents the routes of the Starter. In this case, the structure is as follows:

  • The root directory is represented by the [countryCode] folder. This indicates a dynamic route based on the country code. The this will be populated by the countries you set up in your Medusa server. The param is then used to fetch region specific prices, languages, etc.
  • Within the root directory, there two Route Groups: (checkout) and (main). This is done because the checkout flow uses a different layout. All other parts of the app share the same layout and are in subdirectories of the (main) group. Route Groups do not affect the url.
  • Each of these subdirectories may have further subdirectories. For instance, the account directory has addresses and orders subdirectories. The orders directory further has a details subdirectory, which itself has a dynamic [id] subdirectory.
  • This nested structure allows for specific routing to various pages within the application. For example, a URL like /account/orders/details/123 would correspond to the account > orders > details > [id] path in the router structure, with 123 being the dynamic [id].

This structure enables efficient routing and organization of different parts of the Starter.

/lib directory

The lib directory contains all utilities like the Medusa JS client functions, util functions, config and constants.

The most important file here is /lib/data/index.ts. This file defines various functions for interacting with the Medusa API, using the JS client. The functions cover a range of actions related to shopping carts, orders, shipping, authentication, customer management, regions, products, collections, and categories. It also includes utility functions for handling headers and errors, as well as some functions for sorting and transforming product data.

These functions are used in different Server Actions.

/modules directory

This is where all the components, templates and Server Actions are, grouped by section. Some subdirectories have an actions.ts file. These files contain all Server Actions relevant to that section of the app.

/styles directory

global.css imports Tailwind classes and defines a couple of global CSS classes. Tailwind and Medusa UI classes are used for styling throughout the app.

/types directory

Contains global TypeScript type defintions.

middleware.ts

Next.js Middleware, which is basically an Edge function that runs before (almost) every request. In our case it enforces a countryCode in the url. So when a user visits any url on your storefront without a countryCode param, it will redirect the user to the url for the most relevant region.

The region will be decided as follows:

  • When deployed on Vercel and you’re active in the user’s current country, it will use the country code from the x-vercel-ip-country header.
  • Else, if you have defined a NEXT_PUBLIC_DEFAULT_REGION environment variable, it will redirect to that.
  • Else, it will redirect the user to the first region it finds on your Medusa server.

If you want to use the countryCode param in your code, there’s two ways to do that:

  1. On the server in any page.tsx - the countryCode is in the params object:

    export default async function Page({
      params: { countryCode },
    }: {
      params: { countryCode: string }
    }) {
      const region = await getRegion(countryCode)
    
    // rest of code
    
  2. From client components, with the useParam hook:

    import { useParams } from "next/navigation"
    
    const Component = () => {
    	const { countryCode } = useParams()
    	
    	// rest of code
    

The middleware also sets a cookie based on the onboarding status of a user. This is related to the Medusa Admin onboarding flow, and may be safely removed in your production storefront.

Resources

Learn more about Medusa

Learn more about Next.js