Medusa.js is an open-source, composable commerce engine built with Node.js. It provides a headless e-commerce backend with products, orders, customers, payments, and shipping — all accessible via REST and JavaScript SDKs. This guide covers deploying Medusa on a VPS.
Project Setup
# Create Medusa project
npx create-medusa-app@latest my-store
cd my-store
# This creates:
# my-store/
# backend/ - Medusa server
# storefront/ - Next.js storefront (optional)
Backend Configuration
// medusa-config.ts
import { defineConfig, loadEnv } from "@medusajs/framework/utils";
loadEnv(process.env.NODE_ENV || "development", process.cwd());
export default defineConfig({
projectConfig: {
databaseUrl: process.env.DATABASE_URL,
redisUrl: process.env.REDIS_URL,
http: {
storeCors: process.env.STORE_CORS!,
adminCors: process.env.ADMIN_CORS!,
jwtSecret: process.env.JWT_SECRET!,
cookieSecret: process.env.COOKIE_SECRET!,
},
},
modules: [
{
resolve: "@medusajs/medusa/payment",
options: {
providers: [
{
resolve: "@medusajs/medusa/payment-stripe",
id: "stripe",
options: {
apiKey: process.env.STRIPE_API_KEY,
},
},
],
},
},
],
});
Environment Variables
# .env
DATABASE_URL=postgres://medusa:password@localhost:5432/medusa
REDIS_URL=redis://localhost:6379
JWT_SECRET=your-super-secret-jwt-key
COOKIE_SECRET=your-cookie-secret-key
STORE_CORS=https://store.example.com
ADMIN_CORS=https://admin-store.example.com
STRIPE_API_KEY=sk_live_...
Database Setup
# Create database
createdb medusa
# Run migrations
npx medusa db:migrate
# Seed with sample data
npx medusa seed --seed-file=src/scripts/seed.ts
# Create admin user
npx medusa user -e admin@example.com -p securepassword
Production Deployment
# Build
npm run build
# Start
NODE_ENV=production npm start
# With PM2
pm2 start dist/main.js --name medusa
Systemd Service
[Unit]
Description=Medusa E-Commerce
After=network.target postgresql.service redis.service
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/medusa
ExecStart=/usr/bin/node dist/main.js
EnvironmentFile=/opt/medusa/.env
Environment=NODE_ENV=production
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Next.js Storefront
# The storefront communicates with Medusa API
# Install Medusa JS SDK
npm install @medusajs/js-sdk
// lib/medusa.ts
import Medusa from "@medusajs/js-sdk";
export const medusa = new Medusa({
baseUrl: process.env.NEXT_PUBLIC_MEDUSA_URL!,
maxRetries: 3,
});
// Get products
const { products } = await medusa.store.product.list();
// Add to cart
const { cart } = await medusa.store.cart.addLineItem(cartId, {
variant_id: variantId,
quantity: 1,
});
Custom API Routes
// src/api/store/custom/route.ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework";
export async function GET(req: MedusaRequest, res: MedusaResponse) {
const productService = req.scope.resolve("product");
const featured = await productService.listProducts({
tags: ["featured"],
});
res.json({ products: featured });
}
Nginx Configuration
# Backend API
server {
listen 443 ssl http2;
server_name api.store.example.com;
ssl_certificate /etc/letsencrypt/live/api.store.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.store.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:9000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Summary
Medusa.js provides a complete open-source e-commerce backend with all the features needed for production stores: products, variants, collections, orders, customers, payments (Stripe, PayPal), shipping, discounts, and gift cards. Self-hosting on a VPS gives you full control over your commerce data with zero transaction fees from the platform (only payment processor fees). The headless architecture lets you build custom storefronts with Next.js, Gatsby, or any frontend framework.