DEV Community

Gun
Gun

Posted on • Updated on

How to Build an Electronic Commerce Store with Medusajs

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:

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.

  1. Install the Medusa CLI tool with the following command:
yarn global add @medusajs/medusa-cli
Enter fullscreen mode Exit fullscreen mode
  1. Create your Medusa application with this command:
yarn create medusa-app
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

After executing those commands, visit localhost:8000 to view your storefront.

storef.PNG

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: [],
}
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
       ...
  )
}

...
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

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 />
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
  • <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,
    },
  },
]
Enter fullscreen mode Exit fullscreen mode

Lastly, edit storefront/next.config.js file like this:

images: {
    domains: ["<YOUR_BUCKET_NAME>.s3.amazonaws.com"],
  },
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Then add this environment variable to your Medusa backend:

ALGOLIA_APP_ID=<YOUR_APP_ID>
ALGOLIA_ADMIN_API_KEY=<YOUR_ADMIN_API_KEY>
Enter fullscreen mode Exit fullscreen mode

<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",
          ],
        },
      },
    },
  },
]
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • <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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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,
    },
  },
]
Enter fullscreen mode Exit fullscreen mode

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_...
Enter fullscreen mode Exit fullscreen mode

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_...
Enter fullscreen mode Exit fullscreen mode

The last part of Stripe integration consists of setting it up in the Medusa admin by adding a payment provider.

  1. Go to Settings → Regions.
  2. Select a region to edit.
  3. Click on the icon at the top right of the first section on the right.
  4. Click on Edit Region Details from the dropdown.
  5. Under the provider's section, select the payment providers you want to add to the region. Here it's Stripe.
  6. Unselect the payment providers you want to remove from the region.
  7. Click Save.

Finally, in your storefront, add the following environment variable:

NEXT_PUBLIC_STRIPE_KEY=<YOUR_PUBLISHABLE_KEY>
Enter fullscreen mode Exit fullscreen mode

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:

store5.PNG

Click on the store item in the navigation bar to open the store:

store7.PNG

Add some products to your cart:

!https://www.learn-dev-tools.blog/wp-content/uploads/2023/03/store8-1024x467.png

Checkout:

store9.PNG

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.