The demand and supply of goods and services keep evolving daily. Businesses need to keep an eye on these evolutions to adopt the right ecommerce platform to distribute their goods and services to various end users.
Headless commerce is becoming increasingly popular because of its adaptability and scalability. A great option for constructing a headless commerce store is Medusa, an open source and scalable ecommerce engine. Next.js offers a robust framework for building storefronts.
With the help of Medusa and Next.js, you can develop a powerful and scalable online store that is tailored to the particular requirements of your company or business. Regardless of your experience as a developer or online retailer, this tutorial will guide you on building and customizing an electronic store.
Here’s a demo of the application with Medusa and Next.js by following this tutorial:
demo medusa electronic store.mp4
What Will You Learn?
- Set up a Storefront with Medusa’s Next.js default starter template.
- Add product using the admin dashboard.
- Display products in your storefront.
- Customize your storefront.
- Add a Search option to your store.
- Add a Payment option to your store.
You can find the code for this tutorial in this GitHub Repository.
What is Next.js?
Next.js is an open-source React framework for building user-friendly web applications. React is a JavaScript library for building interactive user interfaces. Next.js enables server-side rendering and requires minimal or no configuration.
Medusa offers two storefront starters: Next.js and Gatsby. It's easy to install them with the CLI command. Medusa Next.js storefront has many ecommerce pre-build features like a shopping cart, product display, payment processing, and more.
What is Medusa?
Medusa is an open-source digital commerce infrastructure built with Node.js and provides many ecommerce features such as RMA flows, product and collection management, order management, customization, and more.
These are some features that set Medusa apart from other ecommerce platforms. Medusa also offers a great developer experience, allowing developers to create amazing and scalable stores with minimal effort.
Medusa's headless architecture enables you to build your store with the framework or language of your choice. There are no constraints, as you can use Medusa's API to connect the Medusa admin to the storefront to perform actions like the product, customer, order, payment management, and many more.
Creating your Electronic Commerce Platform
This section highlights the steps to build your electronic store with Next.js and Medusa.
Prerequisites
Before you begin, make sure you have the following:
- Nodejs version 14 or later
- Git
- Yarn or Npm(This tutorial uses Yarn)
- A code editor like VSCode
- An Algolia account
- A Stripe account
- S3 for file upload service
You will find all the resources used in this tutorial, such as icons and images in the Git repository.
How to Set Up the Medusa Server for the Electronic Store
If you have everything installed, follow these steps to set up your Medusa project.
- Install the Medusa CLI tool with the following command:
yarn global add @medusajs/medusa-cli
- Create your Medusa application with this command:
yarn create medusa-app
Upon executing, this command will ask you where you which to install your project. Enter a name there; in this tutorial, it is ElectronicStore
. Then, press enter. For this tutorial, choose the Medusa-starter-default
for the backend and the Next.js starter
template for the storefront.
Normally you should have the same information as the screenshot below.
![How to Build an Electronic Commerce Store with Medusa and Nextjs]https://www.learn-dev-tools.blog/wp-content/uploads/2023/03/starter-1024x302.png
Upon the execution of this command, Medusa will create three folders in the ElectronicStore
: storefront, admin, and backend.
To start each part of the application, open the three command line/terminal tabs and run the following command with respect to each folder:
# Medusa server
cd ElectronStore/backend
yarn start
# Admin
cd ElectronStore/admin
yarn start
# Storefront
cd ElectronStore/storefront
yarn dev
After executing those commands, visit localhost:8000
to view your storefront.
Similarly, visit your admin dashboard by opening your browser on localhost:7000
. 7000 is the default admin port.
!https://www.learn-dev-tools.blog/wp-content/uploads/2023/03/admin-1024x552.png
The next step consists of styling your storefront. This tutorial uses Tailwind CSS very useful for building modern websites. Note that you can equally set up your Medusa admin, Medusa storefront, and Medusa Backend separately.
Styling the Electronic Commerce Storefront
This section shows how to style your storefront using Tailwind CSS. With create-medusa-app
, the Next.js starter template already contains Tailwind. However, you need to configure the tailwind.config.js
as follows:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./app/**/*.{js,ts,jsx,tsx}",
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
// Or if using `src` directory:
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Now that you have successfully added Tailwind to your project, you must customize your storefront.
Customizing the Storefront
Start by changing the style of the header storefront/src/module/layout/templates/nav/index.tsx
with the code below:
const Nav = () => {
const { pathname } = useRouter()
const [isHome, setIsHome] = useState(false)
useEffect(() => {
pathname === "/" ? setIsHome(true) : setIsHome(false)
}, [pathname])
const { toggle } = useMobileMenu()
return (
<div
className={clsx("sticky top-0 inset-x-0 z-50 group", {
"!fixed": isHome,
})}
>
<header className="relative h-16 px-8 mx-auto transition-colors bg-white border-b border-transparent duration-200 group-hover:bg-white group-hover:border-gray-200 border-b-[#f1f1f1]">
<nav
className={clsx(
"text-gray-900 flex items-center justify-between w-full h-full text-small-regular transition-colors duration-200"
)}
>
<div className="flex-1 basis-0 h-full flex items-center">
<div className="block small:hidden">
<Hamburger setOpen={toggle} />
</div>
<div className="hidden small:block h-full">
<DropdownMenu />
</div>
</div>
<div className="flex items-center h-full">
<Link href="/">
<a className="text-xl-semi uppercase">
<img src="/logo.png" alt="" width={50} />
</a>
</Link>
</div>
<div className="flex items-center gap-x-6 h-full flex-1 basis-0 justify-end">
<div className="hidden small:flex items-center gap-x-6 h-full">
{process.env.FEATURE_SEARCH_ENABLED && <DesktopSearchModal />}
<Link href="/account">
<a>Account</a>
</Link>
</div>
<CartDropdown />
</div>
</nav>
<MobileMenu />
</header>
</div>
)
}
export default Nav
This code above changes the navbar by adding a border and logo.
To change the banner image, locate your storefront/src/modules/home/components/hero/index.tsx
, which is the hero section and replace it with the code below:
const Hero = () => {
return (
<div className="h-[90vh] w-full relative">
<div className="text-white absolute inset-0 z-10 flex flex-col justify-center items-center text-center small:text-left small:justify-end small:items-start small:p-32">
<h1 className="text-2xl-semi mb-4 drop-shadow-md shadow-black">
Hi 👋 welcome to my electronic shop
</h1>
<p className="text-base-regular max-w-[32rem] mb-6 drop-shadow-md shadow-black">
The best electronic devices to help you in your daily tasks both in
the professional and personal life.
</p>
<UnderlineLink href="/store">Explore products</UnderlineLink>
</div>
<div className="bg-white h-[90vh] w-full">
The best electronic devices to help you in your daily tasks both
in the professional and personal life.
</div>
<Image
src="/hero2.jpg"
layout="fill"
loading="eager"
priority={true}
quality={90}
objectFit="cover"
alt="computer"
className="absolute inset-0"
draggable="false"
/>
<div className="bg-black h-[90vh] w-full absolute top-0 opacity-50"></div>
</div>
)
}
export default Hero
This code block adds a banner image and text to the hero section.
Next, change how you display feature products in the home section. storefront/src/module/home/components/featured-products/index.tsx
:
const FeaturedProducts = () => {
...
return (
...
<div className="flex flex-col items-center text-center mb-16">
<span className="text-base-regular text-gray-600 mb-6">
Latest products
</span>
<p className="text-2xl-regular text-gray-900 max-w-lg mb-4">
Our newest electronic gadgets to make your life smooth.
</p>
<UnderlineLink href="/store">Explore products</UnderlineLink>
</div>
...
)
}
...
The code above changes the text of feature products of your store.
Change the section just before the footer storefront/src/modules/layout/components/footer-cta/index.tsx
by adding the following code:
const FooterCTA = () => {
return (
<div className="bg-gray-100 w-full">
<div className="content-container flex flex-col-reverse gap-y-8 small:flex-row small:items-center justify-between py-16 relative">
<div>
<h3 className="text-2xl-semi">Check out the lastest gadgets</h3>
<div className="mt-6">
<UnderlineLink href="/store">Explore products</UnderlineLink>
</div>
</div>
<div className="relative w-full aspect-square small:w-[35%] small:aspect-[28/36]">
<Image
src="/hero3.jpg"
alt=""
layout="fill"
objectFit="cover"
className="absolute inset-0"
/>
</div>
</div>
</div>
)
}
export default FooterCTA
Here you are changing the default text as well as the default image.
Now move to the footer file storefront/src/modules/layout/components/footer-nav/index.tsx
and replace it with the following code:
const FooterNav = () => {
const { collections } = useCollections()
return (
<div className="content-container flex flex-col gap-y-8 pt-16 pb-8">
<div className="flex flex-col gap-y-6 xsmall:flex-row items-start justify-between">
<div>
<Link href="/">
<a className="text-xl-semi uppercase">
<img src="/logo.png" alt="" width={50} />
</a>
</Link>
<p className="py-5 text-sm text-[#999]">
Get the best electronics from the best place
</p>
<div className="flex flex-col-reverse gap-y-0 justify-center xsmall:items-center xsmall:flex-row xsmall:justify-between">
<span className="text-xsmall-regular text-gray-500">
© Copyright 2023 ES store
</span>
<div className="min-w-[316px] flex xsmall:justify-end">
<CountrySelect />
</div>
</div>
</div>
<div className="text-small-regular grid grid-cols-3 gap-x-16">
<div className="flex flex-col gap-y-2">
<span className="text-base-semi">Collections</span>
<ul
className={clsx("grid grid-cols-1 gap-y-2", {
"grid-cols-2": (collections?.length || 0) > 4,
})}
>
{collections?.map((c) => (
<li key={c.id}>
<Link href={`/collections/${c.id}`}>
<a>{c.title}</a>
</Link>
</li>
))}
</ul>
</div>
</div>
</div>
</div>
)
}
export default FooterNav
This code snippet above adds new links and a logo in the footer. In the last part of the footer, change the background colour storefront/src/modules/layout/components/medusa-cta/index.tsx
const MedusaCTA = () => {
return (
<div className="py-4 flex justify-center items-center w-full bg-[#333]">
<div className="content-container flex justify-center flex-1">
<a href="https://www.medusajs.com" target="_blank" rel="noreferrer">
<PoweredBy />
</a>
</div>
</div>
)
}
Head to storefront/src/pages/index.tsx
to modify the meta information of the home page:
const Home: NextPageWithLayout = () => {
return (
<>
<Head
title="Home"
description="Get the best electroics for your home and office from the best stores online with secure payment methods."
/>
<Hero />
<FeaturedProducts />
</>
)
}
By the end, you should have a store similar to the screenshot below:
!https://www.learn-dev-tools.blog/wp-content/uploads/2023/03/store1-1024x470.png
Adding Products in the Electronic Commerce Store
By default, Medusa comes with some products on the storefront. You need to add your products. Medusa commonly uses a file service plugin to add products to the admin dashboard.
Installing and Integrating a File Service Plugin (S3)
Simple Storage Service (S3) is a powerful open-source object storage suite available on any public and private cloud. Medusa uses file service plugins to host files such as images.
This tutorial will use AWS S3, but you can use other file services like Space and Minio. You need to have an AWS account and create a bucket if you have none. Equally, you need to create an access and secret key that you will use in the next section to build your store.
When you are done with that, install the S3 plugin in the backend with the command below:
yarn add medusa-file-s3
Then, open your backend/.env
file and add the following:
S3_URL=<YOUR_BUCKET_URL>
S3_BUCKET=<YOUR_BUCKET_NAME>
S3_REGION=<YOUR_BUCKET_REGION>
S3_ACCESS_KEY_ID=<YOUR_ACCESS_KEY_ID>
S3_SECRET_ACCESS_KEY=<YOUR_SECRET_ACCESS_KEY>
-
<YOUR_BUCKET_URL>
corresponds to the URL of your bucket it's generally in the form:http://<YOUR_BUCKET_NAME>.s3-website-<YOUR_BUCKET_REGION>.amazonaws.com
-
<YOUR_BUCKET_NAME>
: The name of your S3 bucket -
<YOUR_ACCESS_KEY_ID
: The access key which was created earlier -
<YOUR_SECRET_ACCESS_KEY>
: The secret key created earlier
To complete the S3 integration, add the following configuration to the array of plugins in the backend/medusa-config.js
file:
const plugins = [
// ...
{
resolve: `medusa-file-s3`,
options: {
s3_url: process.env.S3_URL,
bucket: process.env.S3_BUCKET,
region: process.env.S3_REGION,
access_key_id: process.env.S3_ACCESS_KEY_ID,
secret_access_key: process.env.S3_SECRET_ACCESS_KEY,
},
},
]
Lastly, edit storefront/next.config.js
file like this:
images: {
domains: ["<YOUR_BUCKET_NAME>.s3.amazonaws.com"],
},
Add the domain from where you are uploading your images. corresponds to the name of your bucket. Once you have finished setting up S3, you can add electronic products to your store.
Add Products with Medusa Admin
To add products to your store, head to the admin dashboard (localhost:7000
). The default login credentials are admin@medusa-test.com
and supersecret
. The Medusa admin dashboard connects the Medusa server to help you to manage your store.
Once you logged in, you should have a similar interface as below. Here you can manage your products, orders, customer settings, and more.
!https://www.learn-dev-tools.blog/wp-content/uploads/2023/03/dash-1024x464.png
Head to the product page and delete all the default products by clicking on the three dots at the end and selecting delete
.
!https://www.learn-dev-tools.blog/wp-content/uploads/2023/03/deleteprod-1024x176.png
After removing all the products, click on add new product
button to add some electronic products to the ecommerce store.
!https://www.learn-dev-tools.blog/wp-content/uploads/2023/03/store3-1024x464.png
If you go to localhost:8000/store
you will see your newly-added products.
!https://www.learn-dev-tools.blog/wp-content/uploads/2023/03/store2-1024x469.png
Integration
Now is the time to integrate the two main services: Search and Payment.
Algolia Integration
Algolia is an open-source UI search JavaScript library. It allows you to add advanced search functionalities to your store. Adding this search functionality to your store will greatly improve the user experience and optimize internal search in the electronic commerce store.
To add Algolia to your application, you need to possess an Algolia account. Upon creating your account, follow this documentation to create an Algolia application and then, get your Algolia Application ID, Admin API Key, and Search-Only API Key.
Next, install the Algolia plugin in your store with the following command:
yarn add medusa-plugin-algolia
Then add this environment variable to your Medusa backend:
ALGOLIA_APP_ID=<YOUR_APP_ID>
ALGOLIA_ADMIN_API_KEY=<YOUR_ADMIN_API_KEY>
<YOUR_APP_ID>
and <YOUR_ADMIN_API_KEY>
correspond to the Application ID and Admin API Key mentioned earlier. You can find them on the API Keys page under your Algolia account.
Add the following item into the plugins
array in medusa-config.js
:
const plugins = [
// ...
{
resolve: `medusa-plugin-algolia`,
options: {
application_id: process.env.ALGOLIA_APP_ID,
admin_api_key: process.env.ALGOLIA_ADMIN_API_KEY,
settings: {
products: {
searchableAttributes: ["title", "description"],
attributesToRetrieve: [
"id",
"title",
"description",
"handle",
"thumbnail",
"variants",
"variant_sku",
"options",
"collection_title",
"collection_handle",
"images",
],
},
},
},
},
]
searchableAttributes
are attributes in a product that are searchable while attributesToRetrieve
are attributes to retrieve for each product result.
Now, add the search UI to the storefront so that users can effectively perform product research. Fortunately, Next.js storefront Algolia integration is available out-of-the-box. To get everything ready, make sure the search feature is set to true
in the store.config.json
:
{
"features": {
"search": true
}
}
Then add the environmental variables:
NEXT_PUBLIC_SEARCH_APP_ID=<YOUR_APP_ID>
NEXT_PUBLIC_SEARCH_API_KEY=<YOUR_SEARCH_API_KEY>
NEXT_PUBLIC_SEARCH_INDEX_NAME=products
-
<YOUR_APP_ID>
corresponds to the Application ID. -
<YOUR_SEARCH_API_KEY>
corresponds to the Search-Only API Key. You can find this information in your Algolia API Keys section.
To complete this integration, change the code in src/lib/search-client.ts
to the following:
import algoliasearch from "algoliasearch/lite"
const appId = process.env.NEXT_PUBLIC_SEARCH_APP_ID || ""
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"
If you run your storefront and backend, you will notice that the search feature is available.
!https://www.learn-dev-tools.blog/wp-content/uploads/2023/03/search-1024x553.png
Payment Integration with Stripe
This section will guide you through how to set up Stripe payment methods in your Medusa backend, admin, and storefront. Stripe is one of the simplest ways to accept online payments. It gives you the technical components needed to manage transactions safely. Other payment methods you can use with Medua are Paystack, Klarna, and Paypal.
To add Stripe to your store, you must possess a Stripe account. Like Algolia, you must retrieve your account's API Keys and secrets to connect Medusa to your Stripe account.
In the root directory of the Medusa backend, use the following command to install the Stripe plugin:
yarn add medusa-payment-stripe
Next, you need to add configurations to your stripe plugin. In medusa-config.js
, add the following at the end of the plugins
array:
const plugins = [
// ...
{
resolve: `medusa-payment-stripe`,
options: {
api_key: process.env.STRIPE_API_KEY,
webhook_secret: process.env.STRIPE_WEBHOOK_SECRET,
},
},
]
Head to the dashboard of your Stripe account to retrieve the API Key and secret key. Then, in your Medusa backend, create .env
if it does not exist and add the Stripe key:
STRIPE_API_KEY=sk_...
Next, add Stripe’s webhook in the .env
file. You can get it by heading to the Stripe dashboard and clicking Add an Endpoint. Medusa backend's endpoint, Stripe webhook, is {BACKEND_URL}/stripe/hooks
.
Note: Add this endpoint to its field if you are in production, and replace {BACKEND_URL} with the URL of your backend. Add a description, select at least one action, and then click Add Endpoint. Once the Webhook is created, you’ll see "Signing secret" in the Webhook details. Reveals the secret key by clicking
reveal
it and copying it into your Medusa backend.
STRIPE_WEBHOOK_SECRET=whsec_...
The last part of Stripe integration consists of setting it up in the Medusa admin by adding a payment provider.
- Go to Settings → Regions.
- Select a region to edit.
- Click on the icon at the top right of the first section on the right.
- Click on Edit Region Details from the dropdown.
- Under the provider's section, select the payment providers you want to add to the region. Here it's Stripe.
- Unselect the payment providers you want to remove from the region.
- Click Save.
Finally, in your storefront, add the following environment variable:
NEXT_PUBLIC_STRIPE_KEY=<YOUR_PUBLISHABLE_KEY>
Where <YOUR_PUBLISHABLE_KEY>
corresponds to your Stripe Publishable Key.
If you run your Medusa storefront and backend, add products to your cart, and then proceed to checkout, you can now use Stripe as a payment method. Here is what the final result looks like:
!https://www.learn-dev-tools.blog/wp-content/uploads/2023/03/store4-1024x558.png
You could also check out this Stripe guide for more information regarding its integration
Testing the Store
The final step of this tutorial consists of testing the whole store. While the Medusa server is still running, restart your storefront.
Navigate to localhost:8000
to see the final electronic commerce store:
Click on the store item in the navigation bar to open the store:
Add some products to your cart:
!https://www.learn-dev-tools.blog/wp-content/uploads/2023/03/store8-1024x467.png
Checkout:
View your order:
!https://www.learn-dev-tools.blog/wp-content/uploads/2023/03/store10-1024x465.png
Conclusion
In this tutorial, you learned how to build a headless electronic commerce platform with the Medusa engine, using the Next.js Storefront and integrating services like search and payment using Algolia and Stripe.
However, you can add many other functionalities to this electronic commerce store. Some include gift cards, tax management, custom shipping methods, and Notifications.
Go to the Medusa documentation for more details regarding these functionalities and services.
This article was originally published on the Learn Dev Tools Blog
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.