Set Up a Storefront on Medusa.js in One Weekend

by Emma Rodriguez
Set Up a Storefront on Medusa.js in One Weekend

You've been paying $79/month for a Shopify plan, and every time you check the billing page you think: "There has to be a cheaper way to run a store this small." There is — and it doesn't require a computer science degree to pull off.

Medusa.js is an open-source, self-hosted commerce engine that's been quietly gaining traction among indie sellers and small agencies. It handles products, carts, orders, and payments out of the box, and it costs you nothing in platform fees. You pay for hosting — usually $5–$20/month on a basic VPS — and that's it. If you're doing under $500K in annual revenue, the savings can be real and immediate.

This tutorial walks you through getting a working Medusa storefront off the ground over a weekend. No fluff, no hand-waving. By Sunday evening you'll have a live URL you can share.

Why Medusa Makes Sense for Small Stores

Before we touch the terminal, let's be honest about the trade-offs. Medusa is not a drag-and-drop builder. You'll write a little code (or copy-paste it, which counts). What you get in return:

  • No revenue share, no transaction fees beyond what your payment processor charges.
  • Full data ownership. Your products, customers, and orders live in your own Postgres database.
  • A headless architecture — meaning you can attach any front end you want, from a Next.js storefront to a mobile app, without rebuilding the backend.
  • An active plugin ecosystem covering Stripe, PayPal, SendGrid, Algolia, and more.

The headless part is worth a sentence of plain English: headless commerce just means the store's brain (inventory, pricing, checkout logic) is separated from its face (the website the customer sees). You can redesign the face without touching the brain, and vice versa. For a small store that might rebrand or pivot, that flexibility is genuinely useful.

Is Medusa right for everyone? No. If you sell one product and need to be live by tomorrow morning, a hosted platform is still the faster path. But if you've got a weekend, a modest technical curiosity, and a desire to own your stack, keep reading.

What You'll Need Before You Start

Gather these before Saturday morning so you're not hunting around mid-tutorial:

  1. Node.js 18 or higher installed on your machine. Run node -v in your terminal to check.
  2. A Postgres database. Locally, install Postgres and create a database called medusa_store. On a VPS, most providers (DigitalOcean, Render, Railway) offer a managed Postgres instance for $5–$7/month.
  3. A Stripe account (free to create). You'll use test mode the whole weekend, so no real money moves.
  4. A free Cloudinary account for product image storage — optional but saves you a headache later.
  5. Git installed, and a GitHub account to deploy from.

If you've never opened a terminal before, this project will stretch you. That's okay — stretching is how you grow. But if the word "terminal" makes you want to close the tab, bookmark this for next month and spend this weekend getting comfortable with command-line basics first.

Saturday Morning: Spin Up the Medusa Backend

Open your terminal and run:

npx create-medusa-app@latest my-store

The CLI will ask a few questions — choose the default Next.js storefront when prompted, and say yes to seeding demo data. This single command scaffolds both the backend API and a ready-to-run storefront. It takes about three minutes on a decent connection.

Once it finishes, you'll have two folders: my-store/backend and my-store/storefront.

Navigate into the backend folder and open the .env file. You'll see a line for DATABASE_URL. Paste in your Postgres connection string — it looks like postgresql://user:password@localhost:5432/medusa_store. Save it.

Now run:

cd my-store/backend
npm run seed
npm run dev

If everything is wired correctly, you'll see Server is ready on port 9000 in your terminal. Open http://localhost:9000/health in a browser. You should see {"status":"ok"}. That's your backend alive and breathing.

Spend Saturday afternoon in the Medusa Admin panel. Navigate to http://localhost:7001 (the admin ships with the project), create your first real product, upload a photo, set a price, and add a couple of variants if you have them — sizes, colors, whatever fits your catalog. The admin UI is clean enough that this part feels less like coding and more like filling out a form.

Saturday Afternoon: Wire Up Stripe Payments

Payments are where a lot of tutorials skip the details. Let's not do that.

In your Stripe dashboard, grab your test secret key — it starts with sk_test_. Add it to your backend .env file:

STRIPE_API_KEY=sk_test_YOUR_KEY_HERE

Medusa has a first-party Stripe plugin. Install it:

npm install medusa-payment-stripe

Then open medusa-config.js in your backend folder and add Stripe to the plugins array:

{
  resolve: `medusa-payment-stripe`,
  options: {
    api_key: process.env.STRIPE_API_KEY,
  },
}

Restart the backend (Ctrl+C, then npm run dev again). Head back to the admin, go to Settings → Regions, click your region, and enable Stripe as a payment provider. Done. Your checkout will now process test cards — use 4242 4242 4242 4242 with any future expiry to simulate a successful payment.

Do a test purchase yourself before you move on. It takes two minutes and saves you a panicked Sunday night when a real customer can't check out.

Sunday Morning: Launch the Next.js Storefront

The storefront that shipped with create-medusa-app is a production-ready Next.js app. It's not the prettiest thing out of the box, but it works — and working beats beautiful every time when you're starting out.

In a second terminal window:

cd my-store/storefront
npm run dev

Open http://localhost:8000. You'll see your products, a working cart, and a checkout flow backed by the Stripe test integration you just set up. Click around. Buy something with that test card. Watch the order appear in your admin panel.

Now, a quick customization that makes a big difference: open storefront/src/styles/globals.css and change the primary color to match your brand. It's one CSS variable — --color-brand. Swap in your hex code, save, and the whole storefront updates instantly. Small win, but it makes the store feel like yours.

For your logo, drop an SVG into storefront/public/ and reference it in the Navbar component at storefront/src/modules/layout/components/nav/index.tsx. If you're not comfortable editing JSX yet, just update the store name string in that file — still better than a generic placeholder.

Sunday Afternoon: Deploy and Go Live

You've got a working store on your laptop. Now let's put it on the internet.

Easiest path for the backend: Railway.app. Create a new project, connect your GitHub repo, point it at the backend folder, add your environment variables in Railway's dashboard, and hit Deploy. Railway detects Node.js automatically. A $5/month hobby plan handles a store doing a few hundred orders a month with room to spare.

For the storefront: Vercel is the natural home for Next.js. Connect your repo, set NEXT_PUBLIC_MEDUSA_BACKEND_URL to your Railway backend URL (something like https://my-store-backend.up.railway.app), and deploy. Vercel's free tier is enough to start.

Once both are live, do the full purchase flow one more time — from the public URL, on your phone, with a test card. Check that the order shows up in admin. If it does, you're done. You have a real, self-hosted e-commerce store running on infrastructure you control.

Total monthly cost so far: roughly $5–$12 depending on your Postgres plan. Compare that to $79+ on a hosted platform and the math is pretty clear for a store in its early stages.

Three Things to Do Before You Take Your First Real Order

Before you flip the switch from test mode to live payments, run through this short checklist:

  1. Swap your Stripe test key for a live key. Update the STRIPE_API_KEY environment variable in Railway and redeploy. Takes about 90 seconds.
  2. Set up a transactional email provider. Medusa supports SendGrid and Postmark via plugins. Customers expect an order confirmation email; sending it builds trust immediately. A SendGrid free account covers 100 emails/day — plenty for a new store.
  3. Add a custom domain. Both Railway and Vercel make this straightforward in their dashboards. A real domain costs $10–$15/year and signals legitimacy to customers who've never heard of you.

None of these are optional if you want to look like a real business. All three can be done in under an hour.

You Built Something Real This Weekend

Setting up a self-hosted Medusa storefront isn't a weekend project that just teaches you something — it's a weekend project that produces something. You now have a running store, a payment integration, and a deployment pipeline that costs a fraction of what most hosted platforms charge.

Is there more to learn? Of course. You'll want to dig into Medusa's plugin docs, explore custom shipping providers, and eventually think about caching and performance as your traffic grows. But none of that needs to happen today.

Your next step: add your real product catalog to the admin, run one live test transaction with a $1 product, and confirm the money lands in your Stripe dashboard. Once it does, you're not just learning headless commerce — you're running it.

You've got this.