Migrate from Railway

Move Railway services, their database and variables.

A Railway project is a set of services connected through variable references. On Nodion, a service with its own code becomes an application, workers from the same code become extra processes of that app, and databases become managed databases you attach to the app. Nodion does not read railway.json or railway.toml; Railway itself is retiring Config as Code (hard cutoff 2026-12-01), so you move the settings by hand.

What maps to what

RailwayNodion
ProjectProject
Service with its own codeApplication
Worker service from the same repoExtra process of the app
Railpack or NixpacksNodion buildpacks
DockerfileDockerfile strategy
Start commandProcess command (Processes tab)
Pre-deploy commandRelease command or Procfile release: entry
Cron schedule on a serviceCron job on the app
VariablesEnvironment variables (Environment tab)
References like ${{Postgres.DATABASE_URL}}Attached database that sets DATABASE_URL
Private networking (*.railway.internal)<slug>.internal for databases, <app>.app.internal for apps
PR environmentsPreview environments
VolumesVolumes

1. Create the project and the databases

Create a project and, in it, the databases your Railway project uses, in the region the apps should run in. For Postgres, pick a version at least as new as on Railway. Instead of Redis, Nodion offers Valkey, also attached as REDIS_URL. An empty Valkey is only enough for caches or queues you let drain first; if you need the keys from Redis, move them before you delete the Railway project. More on Databases.

2. Copy the database

Railway databases are private by default. For the dump you reach one in one of two ways: either turn on public access under Settings, Networking; Railway then creates a TCP proxy and sets DATABASE_PUBLIC_URL (Railway docs), and bills traffic over the proxy as egress. Or keep the database private and open a tunnel with the Railway CLI, after linking the project with railway link. Railway's built-in volume backups only restore into the same project, so a move needs pg_dump.

Stop writes from your services, then create the dump as Railway's backup guide shows. Over public access, use the value of DATABASE_PUBLIC_URL from the database service's variables:

bashpg_dump "postgresql://postgres:PASSWORD@PROXY_HOST:PROXY_PORT/railway" \
  --format=custom --no-owner --file=railway.dump

Through the tunnel, first link the project with railway link, then open the tunnel and, in a second terminal, dump against localhost with the port the CLI prints:

bashrailway link
railway connect postgres --tunnel-only

# second terminal
pg_dump "postgresql://postgres:PASSWORD@localhost:TUNNEL_PORT/railway" \
  --format=custom --no-owner --file=railway.dump

In Nodion, open the database's Overview tab and click Enable public access. Once the endpoint no longer shows Provisioning, copy the connection URL (always TLS) and add your own IP under Allowed sources. Then restore:

bashpg_restore --verbose --no-owner --no-acl \
  --dbname "postgresql://nodion:PASSWORD@HOST:PORT/DATABASE?sslmode=require" \
  railway.dump

Use a pg_restore at least as new as the newer of the two servers. Check row counts on the Browse tab, then turn public access off again, and on Railway as well.

3. Create the application and its processes

Create one application per code service from its Git repository. If Railway built with Railpack or Nixpacks, use the Buildpacks strategy (Buildpacks); if it found a Dockerfile, use the Dockerfile strategy. Unlike Railway, Nodion does not pick the strategy for you; you set it.

Railway injects PORT for your services. Nodion sets PORT only for the web process of buildpack apps; on Dockerfile apps the app listens on the web process port (else the image's EXPOSE, else 8080).

If a second service ran from the same repo with only another start command, a worker for example, add it under Processes, New process as another process of the same app and enter the start command there. Move a pre-deploy command to a release: line in the Procfile (buildpacks) or to the app's release command (Settings, in the Preview environments card, where the field shows once previews are enabled, or release_command over the API). It runs once per deploy before web; if it fails, the previous release stays live.

4. Move the variables

Print a service's variables as KEY=value lines (Railway CLI):

bashrailway variable list --kv > railway.env

Paste the lines into Environment, Add many. The Railway CLI does not print sealed variables (Railway docs); set those by hand, as secrets with nodion env set KEY=value --secret. Check values with quotes, and set values that span several lines through the CLI or API.

Nodion has no references like ${{shared.KEY}} or ${{otherService.KEY}}. Check every imported variable: it must hold the actual value, not the reference text. Where a reference pointed at another service, set that service's internal hostname on Nodion instead (<app>.app.internal), or attach the database.

Delete the variables that point at a Railway database (DATABASE_URL, REDIS_URL) again: a variable you set yourself overrides the value of an attached database. Attach the databases with Attach database. Inside Nodion the connection runs without TLS (sslmode=disable); if your code forces SSL, turn that off for this URL.

5. Move cron

On Railway a cron job is its own service that runs and exits (Railway docs). On Nodion you add it on the Cron tab of the app whose code it needs: a five-field schedule in UTC, the command, a timeout of up to 30 minutes, up to 8 jobs per app. It runs with the app's active release and environment variables.

6. Deploy, move the domain, shut down Railway

Deploy and check the Logs tab. Then add the domain on the Domains tab and set the two records Nodion shows: TXT _nodion-challenge.your-domain and a CNAME (an ALIAS at the apex) to the app's default hostname. The certificate follows once the CNAME points at Nodion; expect a few minutes without a valid certificate and lower the TTL beforehand. When everything runs, delete the Railway project; Railway calls this permanent.

bashrailway delete --project my-project --yes

What works differently

  • There are no environments such as production and staging inside one project; use separate apps or projects.
  • There are no shared variables or references; database values come from attaching the database.
  • Cron jobs run on an existing app, not as a service of their own.
  • The CLI fetches logs but cannot follow them; watch them live on the Logs tab.

Next

Nodion compared with Railway, Pricing, Applications and Databases.

Give your agent a cloud.

Earn up to 15 € in credit when signing up.

Continue with GitHub

or with email

Stay in the loop.

Product news, no spam. Unsubscribe anytime.