Moving from Railway
miosa import railway reads a Railway project through Railway’s public API and writes a plan: the MIOSA project, Deploy targets, services, databases and variable names it would create, and everything it cannot carry across.
Nothing is created until you review the plan and apply it.
The same page is the reference for what maps, what does not, and what to do about the secrets.
Before you start
- A Railway token: an account, workspace or project token from Railway’s account settings. MIOSA reads it, never stores it, and never writes it to the plan.
- The MIOSA CLI,
@miosa/cli2.4.0 or newer:
npm install -g @miosa/cli
miosa --version - Assume every secret in the Railway project is compromised. Railway credentials were exposed in 2025, so the import copies names, not values, unless you explicitly ask otherwise.
The three steps
export RAILWAY_TOKEN=... # or --token-file, or a prompt
miosa import railway --project acme-api # review only; nothing is created
miosa import railway --project acme-api --out plan.json
miosa import railway --apply --plan plan.json The review prints what will be created, which variables need a value, and a “Finish by hand” list with the MIOSA command for each item. Every field that cannot be carried appears there; nothing is dropped silently.
If you are already logged in with the Railway CLI, --via railway-cli reads through that session, so no token passes through MIOSA at all.
What maps
| Railway | MIOSA |
|---|---|
| Project | Project |
Environment (production) | the project’s default Deploy target; others with --include-targets |
| Service | Web service, Worker, Private service or Schedule |
| Repository, branch, root directory, Dockerfile | the same |
| Start command | the service’s start command |
| Replicas | replicas (1 to 50) |
| Region | the nearest MIOSA region (us-east, us-west, us-mia) |
| Cron schedule | a Schedule service |
| Variables | variable names, and ${{Service.VAR}} references unchanged |
| Postgres, Redis, MySQL plugins | managed databases |
| Custom domain | listed, and added when the Services domain API is live; until then the exact command is printed |
MIOSA uses the same ${{Service.NAME}} reference syntax as Railway, so a reference keeps working when the service names match.
What does not map
| Railway | What to do |
|---|---|
| Build command | MIOSA builds from the Dockerfile or detects the stack; move it into the Dockerfile or a build script |
| Health check path and timeout | MIOSA checks readiness on the service’s port |
| Restart policy | MIOSA restarts a failed release by policy |
| Sleep on idle, watch patterns, pre-deploy command | no MIOSA equivalent yet; the review lists each one |
| Service volumes | the Services API has no service volumes yet; the review prints miosa volume create and where to attach it |
*.up.railway.app domains | Railway-owned DNS; MIOSA assigns <label>.<org>.miosa.app |
| MongoDB plugins | no managed MongoDB |
| Other environments | reported unless --include-targets, which copies names, not values |
Rotate the secrets
The import refuses to run while a variable has no value, which is deliberate: it should not start a service with a leaked secret.
- Assume every secret in the Railway project is compromised.
- Do not copy values during the import; set new ones on MIOSA.
- Rotate at the provider first (database password, Stripe, SMTP, API keys), then paste the new value into MIOSA.
- Deploy after the new values are set, so the service never starts with a leaked one.
- Delete the old Railway project once the MIOSA one serves traffic.
miosa service vars set <project> <service> STRIPE_KEY=<new value>
miosa service deploy <project> <service> --copy-variables exists for a test project where nothing is sensitive.
It prints the same warning, and it is never the default.
If you only have a config file
railway.json and railway.toml are Railway’s config-as-code. --from-file reads one locally, with no token and no network call:
miosa import railway --from-file ./railway.toml --service-name api The plan has no source, because a config file has none; pass --repo or --image when you apply, or edit the plan.
Undo
Every id the apply creates is recorded as it is created.
miosa import railway --cleanup --state .miosa/import-railway-acme-api.json --yes --cleanup prints exactly what it will delete first, and deletes only those ids.
An interrupted apply continues with --resume.
Railway terms, MIOSA names
| Railway says | MIOSA calls it |
|---|---|
| Project | Project |
| Environment | Deploy target |
| Service | Service (Web service, Worker, Private service, Schedule) |
| Plugin | Database |
| Deploy | Release |
| Variables | Variables |
| Volume | Volume (machine-scoped today) |
| Domain | Public address or custom domain |