---
title: "Deploy Medusa v2 (Worker Mode)"
description: "Medusa v2 with a dedicated background-job worker, search and storefront."
category: "Other"
url: https://railway.com/deploy/medusa-v2-worker-mode
---

# Deploy Medusa v2 (Worker Mode)

Medusa v2 with a dedicated background-job worker, search and storefront.

**[Deploy Medusa v2 (Worker Mode) on Railway](https://railway.com/template/medusa-v2-worker-mode)**

- **Creator:** darseen
- **Category:** Other
- **Total deploys:** 1

## Template content

### Redis https://devicons.railway.com/i/redis.svg

- **Image:** redis:8.2.1
- **Start command:** `/bin/sh -c "rm -rf $RAILWAY_VOLUME_MOUNT_PATH/lost+found/ && exec docker-entrypoint.sh redis-server --requirepass $REDIS_PASSWORD --save 60 1 --dir $RAILWAY_VOLUME_MOUNT_PATH"`

### Worker https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/medusa-light.svg

- **Source:** rpuls/medusajs-2.0-for-railway-boilerplate

### Storefront https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/medusa-light.svg

- **Source:** rpuls/medusajs-2.0-for-railway-boilerplate
- **Start command:** `npm run start`
- **Health check:** /api/healthcheck
- **Public domain:** Yes

### Media-proxy https://devicons.railway.app/asdasd

- **Image:** ghcr.io/railwayapp/function-bun:1.3.0
- **Start command:** `./run.sh aW1wb3J0IHsgczMgfSBmcm9tICJidW4iOwoKY29uc3QgQ0FDSEVfQ09OVFJPTCA9IEJ1bi5lbnYuQ0FDSEVfQ09OVFJPTCB8fCAicHVibGljLCBtYXgtYWdlPTMxNTM2MDAwLCBpbW11dGFibGUiOwoKY29uc3Qgbm90Rm91bmQgPSAoKSA9PiBuZXcgUmVzcG9uc2UoIk5vdCBGb3VuZCIsIHsgc3RhdHVzOiA0MDQgfSk7CgpleHBvcnQgZGVmYXVsdCB7CiAgYXN5bmMgZmV0Y2gocmVxOiBSZXF1ZXN0KTogUHJvbWlzZTxSZXNwb25zZT4gewogICAgY29uc3QgdXJsID0gbmV3IFVSTChyZXEudXJsKTsKCiAgICBpZiAodXJsLnBhdGhuYW1lID09PSAiL3Byb3h5LWhlYWx0aHoiKSB7CiAgICAgIHJldHVybiBuZXcgUmVzcG9uc2UoIm9rIiwgeyBzdGF0dXM6IDIwMCB9KTsKICAgIH0KCiAgICBpZiAocmVxLm1ldGhvZCAhPT0gIkdFVCIgJiYgcmVxLm1ldGhvZCAhPT0gIkhFQUQiKSB7CiAgICAgIHJldHVybiBuZXcgUmVzcG9uc2UoIk1ldGhvZCBOb3QgQWxsb3dlZCIsIHsKICAgICAgICBzdGF0dXM6IDQwNSwKICAgICAgICBoZWFkZXJzOiB7IEFsbG93OiAiR0VULCBIRUFEIiB9LAogICAgICB9KTsKICAgIH0KCiAgICBsZXQga2V5OiBzdHJpbmc7CiAgICB0cnkgewogICAgICBrZXkgPSBkZWNvZGVVUklDb21wb25lbnQodXJsLnBhdGhuYW1lLnNsaWNlKDEpKTsKICAgIH0gY2F0Y2ggewogICAgICByZXR1cm4gbm90Rm91bmQoKTsKICAgIH0KCiAgICBpZiAoIWtleSB8fCBrZXkuaW5jbHVkZXMoIlwwIikgfHwga2V5LmluY2x1ZGVzKCIuLiIpKSByZXR1cm4gbm90Rm91bmQoKTsKCiAgICBjb25zdCBmaWxlID0gczMuZmlsZShrZXkpOwogICAgY29uc3Qgc3RhdCA9IGF3YWl0IGZpbGUuc3RhdCgpLmNhdGNoKCgpID0+IG51bGwpOwogICAgaWYgKCFzdGF0KSByZXR1cm4gbm90Rm91bmQoKTsKCiAgICBjb25zdCBoZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0gewogICAgICAiQ29udGVudC1UeXBlIjogc3RhdC50eXBlIHx8ICJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLAogICAgICAiQ29udGVudC1MZW5ndGgiOiBTdHJpbmcoc3RhdC5zaXplKSwKICAgICAgIkNhY2hlLUNvbnRyb2wiOiBDQUNIRV9DT05UUk9MLAogICAgICAiWC1Db250ZW50LVR5cGUtT3B0aW9ucyI6ICJub3NuaWZmIiwKICAgIH07CgogICAgcmV0dXJuIHJlcS5tZXRob2QgPT09ICJIRUFEIgogICAgICA/IG5ldyBSZXNwb25zZShudWxsLCB7IHN0YXR1czogMjAwLCBoZWFkZXJzIH0pCiAgICAgIDogbmV3IFJlc3BvbnNlKGZpbGUuc3RyZWFtKCksIHsgc3RhdHVzOiAyMDAsIGhlYWRlcnMgfSk7CiAgfSwKfTsK`
- **Health check:** /proxy-healthz
- **Public domain:** Yes

### Postgres https://devicons.railway.com/i/postgresql.svg

- **Image:** ghcr.io/railwayapp-templates/postgres-ssl:18

### Backend https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/medusa-light.svg

- **Source:** rpuls/medusajs-2.0-for-railway-boilerplate
- **Health check:** /health
- **Public domain:** Yes

### MeiliSearch https://raw.githubusercontent.com/meilisearch/meilisearch/main/assets/logo.svg

- **Image:** getmeili/meilisearch:v1.11.3
- **Health check:** /health
- **Public domain:** Yes

## Buckets

- **Bucket**

## Documentation

# 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_EMAIL`** on the Backend before deploying — it becomes
  your Admin login. The matching password is generated for you; read it from the
  Backend service's `MEDUSA_ADMIN_PASSWORD` variable after deploy.
- **Optional:** `STRIPE_API_KEY` + `STRIPE_WEBHOOK_SECRET` for card payments,
  and `RESEND_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](https://github.com/medusajs/medusa) — upstream project
- [Medusa worker mode](https://docs.medusajs.com/learn/deployment/general) — the production topology this template implements
- [medusajs-2.0-for-railway-boilerplate](https://github.com/rpuls/medusajs-2.0-for-railway-boilerplate) — the backend and storefront source this template builds
- [Meilisearch](https://www.meilisearch.com/) — product search
- [Railway Storage Buckets](https://docs.railway.com/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:

```bash
railway ssh --service Backend -- sh -lc \
  "cd /app/.medusa/server &amp;&amp; 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.



## Similar templates

- [Rocky Linux](https://railway.com/deploy/rocky-linux) — [Jul'26] Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀
- [Foundry Virtual Tabletop](https://railway.com/deploy/X5tR6G) — A Self-Hosted & Modern Roleplaying Platform
- [Letta Code Remote](https://railway.com/deploy/letta-code-remote) — Run a Letta Code agent 24/7. No inbound ports, just deploy.

Open this page in a browser: https://railway.com/deploy/medusa-v2-worker-mode
