
Deploy Medusa 2 | (Just Updated) Headless Commerce API + Admin, 3 Services Not 6
Commerce API + Admin, prebuilt: 3 services, migrations on every deploy.
postgres
Just deployed
/var/lib/postgresql
redis
Just deployed
/data
Just deployed
/app/static
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
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.
Template Content