---
title: "Deploy Medusa 2 | (Just Updated) Headless Commerce API + Admin, 3 Services Not 6"
description: "Commerce API + Admin, prebuilt: 3 services, migrations on every deploy."
category: "CMS"
url: https://railway.com/deploy/medusa-2-or-just-updated-headless-commer
---

# Deploy Medusa 2 | (Just Updated) Headless Commerce API + Admin, 3 Services Not 6

Commerce API + Admin, prebuilt: 3 services, migrations on every deploy.

**[Deploy Medusa 2 | (Just Updated) Headless Commerce API + Admin, 3 Services Not 6 on Railway](https://railway.com/template/medusa-2-or-just-updated-headless-commer)**

- **Creator:** SuperSlowSloth
- **Category:** CMS

## Template content

### postgres

- **Image:** postgres:17.10-alpine

### redis

- **Image:** redis:8.2.1-alpine
- **Start command:** `/bin/sh -c 'chown -R redis:redis /data && exec docker-entrypoint.sh redis-server --requirepass "$REDIS_PASSWORD" --appendonly yes --dir /data'`

### medusa

- **Image:** ghcr.io/bon5co/medusa-railway:2.17.2
- **Public domain:** Yes

## Documentation

# Deploy and Host Medusa 2 on Railway

Medusa is the open-source headless commerce platform behind stores that outgrew a hosted
cart: a complete commerce API — products, variants, inventory, carts, orders, fulfilment,
promotions, tax, regions, multi-currency pricing — plus the Admin dashboard, plus a workflow
engine you extend in TypeScript. This template deploys Medusa 2.17.2 as a prebuilt image with
PostgreSQL and Redis in three billed services instead of six, an admin account seeded before
the store is reachable, and database migrations that run on every deploy rather than only on
the first one.

## About Hosting Medusa 2

Medusa is a Node application that keeps every piece of commerce state in PostgreSQL and uses
Redis for its event bus, workflow engine and cache. The Admin dashboard is not a separate
service — it is a static bundle the same server hosts — so a working store is three services,
not six.

Three Railway-specific details decide whether the deployment is sound, and all three are
handled here.

**Migrations run on every boot.** The launch script every other Medusa template on Railway
uses decides whether the database needs work by checking whether the `user` table exists, and
`db:migrate` sits inside that branch — so migrations run exactly once, on the very first boot,
and never again. Any later version bump then starts against the schema the previous version
left behind. This image migrates every time it starts.

It also connects to PostgreSQL correctly whichever PostgreSQL you point it at. Medusa infers
its TLS setting from the connection string alone — anything that is not `localhost` gets TLS
demanded of it — and its migration runner retries a failing connection forever rather than
reporting the error, so against a database without TLS `medusa db:migrate` prints "Migrations
table created successfully" and then does nothing at all: no migration SQL, no lock, no error,
just a silent reconnect loop. This image probes the server once and configures the connection
from what the server actually offers, which is why its PostgreSQL does not have to be a
special TLS-enabled build.

**The admin password is the one you set, today.** Medusa's CLI can only create an account; it
has no update or reset command, so on other templates the password applied on first boot can
never be changed again while the Railway variable panel happily shows a new value. Here a
later boot resets the password to whatever the variable currently holds, and the container
refuses to start on an empty one rather than serving a store nobody can sign in to.

**Nothing phones home.** The launch utility used across this category POSTs your Railway
project ID and public shop URL to the template author's own server on every boot, shipped as
a default in the deploy form. This template reports to nobody.

Redis is deployed with a password it actually enforces, append-only persistence, and no public
TCP proxy. Uploaded product images live on a volume instead of the disposable filesystem.

Typical cost is about **$10–15/month** on Railway for the application, PostgreSQL and Redis.
Medusa is free and open source under the MIT licence.

## Common Use Cases

- **A headless backend for a custom storefront** — Next.js, Astro, Remix or a native app
  against the Store API, with the Admin dashboard included.
- **B2B and multi-region commerce** — price lists, customer groups, multi-currency and
  region-specific tax and fulfilment rules out of the box.
- **Commerce inside an existing product** — subscriptions, digital goods or marketplace flows
  built as Medusa workflows and API routes.
- **Migrating off a hosted cart** — own the data model, the checkout logic and the database.

## Dependencies for Medusa 2 Hosting

- A Railway account — roughly $10–15/month for the app, PostgreSQL and Redis
- PostgreSQL (included in this template, with a persistent volume)
- Redis (included in this template, password-protected, with a persistent volume)
- A storefront, if you want a shopfront — this template is the commerce API and Admin

### Deployment Dependencies

- [Medusa source](https://github.com/medusajs/medusa)
- [Medusa documentation](https://docs.medusajs.com/)
- [Wrapper image source](https://github.com/bon5co/medusa-railway)
- [Railway private networking](https://docs.railway.com/guides/private-networking)

### Implementation Details

Three services deploy on Railway's private network. The `medusa` service runs
`ghcr.io/bon5co/medusa-railway:2.17.2`, which builds the upstream Railway boilerplate at a
pinned commit once, at image build time, instead of on the deployer's build minutes; the
`postgres` service runs `postgres:17.10-alpine` with a volume at `/var/lib/postgresql`; the
`redis` service runs `redis:8.2.1-alpine` with `--requirepass`, `--appendonly yes` and a
volume at `/data`, reachable only from inside your project.

Prebuilding the dashboard is possible because Medusa bakes its backend URL into the Admin
bundle at build time and treats an empty value as a value: built with an empty backend URL,
the dashboard issues same-origin requests, which is correct for every deploy of this
template, where Admin and API share one hostname.

On boot the wrapper waits for PostgreSQL, decides how to negotiate TLS with it and says so in
the log, runs `db:migrate` and `db:sync-links`, seeds the demo catalogue once behind a marker
on the database (set `MEDUSA_SEED_DEMO_DATA=false` to skip it), creates the admin account or
resets its password, then starts the server on Railway's injected port. The first boot runs
several minutes of migrations before anything listens, so the service is published without an
HTTP health check.

After deploying, sign in at `https://YOUR-DOMAIN/app` with the generated `MEDUSA_ADMIN_EMAIL`
and `MEDUSA_ADMIN_PASSWORD` from the service variables. The Store and Admin APIs are at
`/store` and `/admin`; create a publishable API key in the dashboard before pointing a
storefront at it.

## Why Deploy Medusa 2 on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your
infrastructure so you don't have to deal with configuration, while allowing you to
vertically and horizontally scale it.

By deploying Medusa on Railway you get managed HTTPS, private networking between the API and
its datastores, persistent volumes for PostgreSQL, Redis and product images, and generated
secrets — with an image that is pulled rather than compiled on every deploy, and a boot
sequence whose migrations reach the database instead of retrying in silence.


## Similar templates

- [Libredesk - Complete Setup](https://railway.com/deploy/libredesk-complete-setup) — [Jul'26] Complete self-hosted omnichannel customer support desk.
- [Paperless-ngx](https://railway.com/deploy/paperless-ngx-3) — Document management with OCR on Railway with PostgreSQL and Redis
- [Instatic CMS - Postgres](https://railway.com/deploy/instatic-cms-postgres) — Design, build and manage powerful static sites from state-of-the-art CMS

Open this page in a browser: https://railway.com/deploy/medusa-2-or-just-updated-headless-commer
