Deploy Medusa v2 (Worker Mode)
Medusa v2 with a dedicated background-job worker, search and storefront.
Redis
Just deployed
/data
Just deployed
Just deployed
Media-proxy
Just deployed
Just deployed
/var/lib/postgresql/data
Just deployed
MeiliSearch
Just deployed
/meili_data
Bucket
Bucket
Just deployed
Deploy and Host Medusa on Railway
Medusa is an open-source commerce platform: a headless Node.js backend with a full Admin dashboard, plus a Next.js storefront. This template runs it the way Medusa documents for production — API traffic and background jobs split into two independently scalable services instead of one process doing both.
About Hosting Medusa
Deploying provisions seven services: a Medusa Backend in server mode, a
Worker in worker mode, Postgres, Redis, Meilisearch, a Next.js
Storefront, and a read-only media proxy in front of a Railway Storage
Bucket. Backend and Worker build the same repository, so the first deploy takes
roughly 10–15 minutes. On a cold project the Backend runs migrations and seeds
demo catalog data on first boot, while the Worker restarts a few times until
that schema exists — this is expected and self-healing, not a failure. Only
Backend, Storefront, Meilisearch, and the media proxy get public domains; the
Worker deliberately has none.
Common Use Cases
- Running a production storefront where checkout, emails, and webhooks must not compete with API request handling for CPU
- Catalogs large enough that Meilisearch indexing and scheduled jobs need their own compute budget
- A customizable Shopify alternative you fully own, with the Admin, Store API, and storefront on one platform
Dependencies for Medusa Hosting
- No external accounts are required. Postgres, Redis, Meilisearch, and object storage are all provisioned by the template.
- Change
MEDUSA_ADMIN_EMAILon the Backend before deploying — it becomes your Admin login. The matching password is generated for you; read it from the Backend service'sMEDUSA_ADMIN_PASSWORDvariable after deploy. - Optional:
STRIPE_API_KEY+STRIPE_WEBHOOK_SECRETfor card payments, andRESEND_API_KEY+RESEND_FROM_EMAIL(or the SendGrid pair) for transactional email. Each feature turns on only when its full pair is set.
Deployment Dependencies
- Medusa — upstream project
- Medusa worker mode — the production topology this template implements
- medusajs-2.0-for-railway-boilerplate — the backend and storefront source this template builds
- Meilisearch — product search
- Railway Storage Buckets — media storage
Implementation Details
Worker mode. The two Medusa services run identical code and differ only in two variables:
| Backend | Worker | |
|---|---|---|
MEDUSA_WORKER_MODE | server | worker |
MEDUSA_DISABLE_ADMIN | false | true |
| Public domain | yes | no |
| Healthcheck | /health | none |
They share the same Postgres and Redis, which is how jobs are handed over — Medusa's Redis event bus and workflow engine are the queue. Scheduled jobs and subscribers execute only on the Worker.
First boot ordering. Railway has no equivalent of compose's
condition: service_completed_successfully. The Backend owns migrations and
seeding; the upstream launcher already skips seeding when
MEDUSA_WORKER_MODE=worker, so the two never race to migrate. The Worker is
given restartPolicyType: ALWAYS and no healthcheck, so it retries harmlessly
until the schema is in place rather than failing the deploy.
Ports are pinned. PORT is set explicitly on Backend (9000), Storefront
(3000), Meilisearch (7700), and the media proxy (8080). Railway's healthcheck
probes the canonical PORT, so leaving it implicit is the most common cause of
a deploy that serves traffic fine but never goes healthy.
Media proxy. Railway Storage Buckets have no public URL, but product images
must be browser-readable. A small Bun function serves objects read-only —
GET/HEAD only, everything else gets 405 — and the bucket credentials never
leave the private network. S3_FILE_URL points at this proxy's domain.
Meilisearch traffic is split. The Backend indexes over the private network
(http://${{MeiliSearch.RAILWAY_PRIVATE_DOMAIN}}:7700); only the Storefront uses
the public origin, because browsers query the index directly.
Scaling the Worker. The upstream config does not enable
@medusajs/locking-redis, so distributed locks are per-instance. That is safe
here because scheduled jobs run on a single Worker — but add the Redis locking
module before scaling the Worker past one replica, or two replicas can run the
same scheduled job concurrently. The Backend scales horizontally without this
caveat.
If Admin login fails. The upstream first-boot check treats "the user table
exists" as "already seeded". If a first boot is interrupted after migrations but
before the admin user is created (for example by editing a variable mid-deploy),
seeding is skipped forever and no admin exists. Recreate it from the Backend
service shell:
railway ssh --service Backend -- sh -lc \
"cd /app/.medusa/server && npx medusa user -e you@example.com -p 'your-password'"
Why Deploy Medusa 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 are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.
Template Content
Redis
redis:8.2.1Media-proxy
ghcr.io/railwayapp/function-bun:1.3.0MeiliSearch
getmeili/meilisearch:v1.11.3Bucket
Bucket
