DeploymentAugust 13, 202611 min read

Railway Alternatives: What You're Actually Detaching From

Every list of Railway alternatives ranks platforms. None of them tells you what you have to unpick first, and that is the part that takes the weekend.

RThe Runsite Team

This is the third list of Railway alternatives you have opened this morning, and by now the pattern is visible: each one is written by a platform, and each one comes first in its own ranking. The tables disagree about who wins and agree about the format, which is a feature matrix comparing things you will not care about in a month.

None of them answers the question you actually have. You are not choosing a platform in the abstract. You have a project on Railway that works, and the thing standing between you and any of these names is the amount of unpicking nobody has quantified for you.

Two adjacent questions are deliberately out of scope here. If you want two named managed platforms held against each other, that is done in Render vs Railway. If the real question is whether the platform layer should run on a server you administer, the ledger for that is in self-hosted PaaS versus managed. What follows assumes you are leaving and want to know what leaving costs.

Why people leave Railway

Three reasons recur, and they arrive at different stages. The first is that the bill moves. Railway meters actual consumption as of writing, which is honest and also means that a retry loop, a worker draining a queue that keeps refilling, or a job that was meant to run nightly can be billed as legitimate work and noticed at the end of the month. The second is the free allowance running out, and for people who have been around a while, the memory of a free tier that changed shape once already. The third arrives latest: a ceiling you meet while growing, whether that is the shape of the pricing at scale or the operational surface you want around a production service.

None of that is an indictment. Railway does something genuinely well, which is making an architecture legible as a graph rather than as a list of unrelated dashboard entries, and shortening the distance from a repository to a running application about as far as anyone has managed. The reasons above are reasons to leave, not evidence that staying is a mistake. If none of them describes your situation, the rest of this page is not trying to move you.

What you're actually detaching

Every list of alternatives makes the same silent assumption: that your application is a container you can pick up and set down somewhere else. On Railway it usually is not. What you have is a project, and a project is a graph: services that know about each other, data that lives inside the same boundary as the code, and a build nobody wrote down. The four things below are what that graph costs to take apart. None of them appears in a feature matrix, and all of them surface in the first hour, not the last.

The variables that are links, not values

As of writing, services on Railway can reference each other's environment variables, so the connection string your application reads is a reference that gets resolved at deploy time rather than a literal you typed. This is a good feature and it is why the graph is convenient to build. It also means that exporting your environment gives you a page of pointers rather than a page of values, and that the resolution happens inside the platform you are leaving. The first symptom is an application that starts on the new host and cannot find its database, and the fix is to work out by hand what each reference was actually pointing at.

text
# What the graph looks like from inside the project
DATABASE_URL = ${{ Postgres.DATABASE_URL }}      <- resolved by the platform
REDIS_URL    = ${{ Redis.REDIS_URL }}            <- resolved by the platform
API_BASE     = ${{ api.RAILWAY_PUBLIC_DOMAIN }}  <- resolved by the platform

# What every other platform expects you to hand it
DATABASE_URL = postgresql://user:pass@host:5432/dbname
REDIS_URL    = redis://user:pass@host:6379
API_BASE     = https://api.example.com

# The gap between those two blocks is manual work,
# and it is discovered at the moment the app fails to boot.

The databases that live inside the project

Postgres and Redis on Railway are provisioned as services sitting next to the application inside the same project, as of writing, rather than as an external endpoint your application happens to point at. That is the difference between changing a connection string and performing a migration. Leaving means getting the data out, finding it somewhere to live, and verifying that what came out goes back in, which for anything with real rows in it is the longest single task in the move. It is also the one people schedule last, because the application is the visible part and the database is not. If you are moving to managed PostgreSQL hosted in the EU or anywhere else, the restore is the step worth rehearsing before the day you need it.

The build you never wrote

Railway builds an image from your source without requiring a Dockerfile by default, as of writing, detecting the stack and assembling the image for you. The convenience is real and the consequence is quiet: there may be no build definition in your repository, which means there is no artifact you own and no description of how the running thing was produced. Why that matters beyond this one migration is worked through in how git push to deploy actually works. The artifact is the part that makes a deploy reproducible, and a build that exists only inside a vendor's pipeline is a build you cannot take with you.

The volume that doesn't come with you

If your service has attached storage, whatever is in it is not part of the repository and not part of the database dump. Uploaded files, generated assets, a SQLite file somebody added early and forgot about: these move only if you move them deliberately. No comparison table has a row for this, and it is the item most likely to be discovered after the switchover instead of before. Moving that content to object storage with no egress charges is worth doing whether or not you change platforms, because it turns a machine-shaped dependency into an addressable one.

The checklist to run before you pick anything

The useful order is the opposite of the obvious one. Rather than choosing a destination and then discovering what does not travel, reduce what ties you to the current platform first. Every item below can be done today, on Railway, without deciding anything about where you are going.

  • Write a Dockerfile and build the image locally. If it builds on your machine and runs, you own the build. This single step converts a platform-detected application into a portable one, and it is the item that unblocks every other option including staying.
  • Flatten the variable graph into a plain file. Go through every reference and write down the value it resolves to. Do it while the platform is still there to tell you, rather than at two in the morning while an application refuses to boot.
  • Take a database dump and restore it somewhere else. Not just take it. Restore it, into a throwaway instance, and point something at it. A dump you have never restored is a hypothesis.
  • Move volume contents into object storage. Anything written to attached disk is the least portable thing you own. Once files are addressed by URL, the service becomes stateless and the move becomes a deploy rather than an operation.
  • Deploy once from a clean clone. Fresh checkout, no local state, no manual steps you have forgotten you perform. Whatever fails here is exactly what would have failed on the new platform, discovered on a day when nothing depends on it.

The point of doing this first

None of these five steps requires you to have chosen a destination, and none is wasted if you decide to stay. What they buy is optionality: after them, the difference between platforms is a comparison you can actually make, because the cost of being wrong has dropped from a weekend to an afternoon. Migrations get frightening in proportion to how much of the system lives somewhere you cannot inspect.

Three groups, and the constraint that picks one

Once the project is portable, the candidates sort themselves into three groups, and which group you want is decided by which constraint is actually binding. The mistake worth avoiding is picking a group by preference and discovering later that it does not address the thing that made you move.

What is actually bindingThe group that addresses itWhat changesWhat does not
The bill is unpredictableAnother managed platform, US-operatedBilling shape, interface, the region listWhose law governs your customers' data
The invoice is simply too largeRun the platform layer yourselfMonthly cost, and how much of the operations you ownThat somebody has to be awake when it breaks
A customer asked whose law appliesA European operating companyThe sentence you send to a security reviewThe amount of migration work, which is the same either way
Sorted by the constraint rather than by rank. The last column is the one that tends to go unread.

The first group is the lateral move, and it is the most common one. Render, Fly.io and the other US-operated managed platforms will change how you are billed and how the dashboard feels, and several of them are genuinely better than Railway at specific things. What that move does not touch is jurisdiction, since a US company operating a Frankfurt region remains a US company. That trade is examined in detail in Render vs Railway, including the case where the migration is motivated by something the migration does not change.

The second group is running the platform layer on infrastructure you rent, with Coolify, Dokploy, Dokku or Kamal on European hardware from Hetzner, Scaleway, OVHcloud, Exoscale or UpCloud. The invoice drops and the operating system, the Docker disk, the proxy and the backups become yours. That exchange is priced honestly in what self-hosting a PaaS actually costs, which is the right page for the open-source and self-hosted end of this question.

The third group is European managed platforms, where the operating company is itself in the EU: Clever Cloud, Scalingo, Upsun and Runsite among them. This is the only group that changes the answer you give when a customer asks whose law governs their data, and it is also the group nobody puts in a ranked list, since the lists sort by feature count rather than by operator. What "European" can legitimately mean, and which of its meanings survives a procurement questionnaire, is set out in choosing a European Heroku alternative.

What the move actually costs

With the checklist done, the move itself is smaller than it looks and lands in a predictable order. The application is the easy part: a Dockerfile you already wrote, a repository connection, a first deploy that either works or tells you what is missing. The variables need care but not much time. What takes real time is the data, and the schedule should be built backwards from it.

The failures worth planning for are the ones that come from the graph rather than from the new platform. A reference that resolved to something you never looked at. A service that talked to another over an internal address that no longer exists. A cron or worker that was configured in a dashboard rather than in the repository, and therefore does not exist in your clone at all. Each is small on its own, and each is the kind of thing that turns a two-hour job into an evening because it is invisible until something calls it.

Plan the move backwards from the database

Everything else can be redone in minutes if it goes wrong; the data cannot. Decide first how the dump is taken, how long the restore runs, and what happens to writes that arrive during it. If the answer to the last one is a short maintenance window, that is fine, as long as it is a decision you made and not one you discovered.

How Runsite handles it

For the European group, concretely, and starting with what will not help you. There is no import tool. Runsite does not read your Railway project, does not convert a variable graph, and does not migrate a database for you; the checklist above is work you do yourself regardless of where you land. The second thing is pricing shape: Runsite charges fixed monthly plans rather than metering consumption, so an application that idles most of the day may well cost less on a consumption meter than it does here. Web services on EU infrastructure start at €5/mo and run up to 8 vCPU and 16 GB as of writing, with a free tier covering one service at 0.1 vCPU and 256 MB.

The third limitation is regions: there is one, Frankfurt, Germany. Against a platform advertising a dozen, that is a short list, and if you need to serve Singapore from Singapore it is the wrong answer. What the single region buys is the sentence in the third row of the table above. Your containers, environment variables, build artifacts and logs stay inside the EU, there is no replication to non-EU regions, and a signed GDPR data processing agreement comes with every plan including the free one, with a European company named in it as the processor.

The parts that make the checklist pay off are ordinary. Your Dockerfile is used when you supply one, and the stack is detected for Next.js, Django, Rails, FastAPI and others when you do not. Connect a repository on GitHub, GitLab or Bitbucket and a webhook builds on every push; releases are rolling behind a configurable health check, a failed check returns to the previous healthy version, and every pull request gets an environment on its own URL. A deploy takes around 30 seconds as of writing, and rollbacks with deploy history are on the Pro plan (€25/mo). On the free tier, active applications do not cold-start; a service sleeps only after 14 days idle. Alongside it sit managed PostgreSQL hosted in the EU and managed Redis for caches and job queues from €5/mo, which is where the two services that currently live inside your Railway project would go. Setup details are in the Runsite docs.

The short version

The ranked lists are answering a question you do not have. What decides how hard leaving Railway is has nothing to do with which platform tops which table, and everything to do with four things inside your current project: variables that are references rather than values, databases that live inside the project boundary, a build that was produced without a Dockerfile, and whatever is sitting on an attached volume. Take those apart first, in that order, and the destination becomes a choice instead of a commitment.

Then pick the group by the constraint that is actually binding. Another US-operated platform if the billing model is the problem, your own server if the invoice is, a European operating company if somebody has started asking whose law applies to your customers' data. The last one is the only question the other two cannot answer, and it is far cheaper to settle before a migration than after. Deploying one service on a European platform that builds from your own Dockerfile is a short way to find out whether the checklist actually made you portable.

FAQ

Frequently Asked Questions

Common questions about this service.

Several platforms offer a free tier, but the useful question is not whether one exists. What matters is what that tier does to an idle application. Most of them stop the container after a period without traffic, which means the next visitor waits for it to start again, and that visitor is usually the one you cared about: someone following a demo link, or a webhook that fires twice a week. The mechanics of that wait are covered in the Runsite article on cold starts and why free-tier apps fall asleep. Two other things are worth checking on any free plan. What happens when the monthly allowance runs out, since the service may suspend instead of degrading, and what happens to the free database, which on most platforms expires well before the free application does. On Runsite's free tier, as of writing, one web service runs at 0.1 vCPU and 256 MB, active applications do not cold-start, and a service sleeps only after 14 days idle.

The open-source options are self-hosted control planes, not hosted platforms, which makes them a different kind of thing rather than a cheaper version of the same thing. Coolify is the most widely used, with Dokploy, Dokku and Kamal covering nearby ground, and all of them run on infrastructure you rent, which in Europe usually means Hetzner, Scaleway, OVHcloud, Exoscale or UpCloud. What you gain is a much smaller invoice and full control of the box. What you take on is the operating system, the Docker disk, the reverse proxy, the certificates, the backups and the upgrades of the control plane itself, plus a single failure domain if everything runs on one server. Whether that exchange is worth it depends on how you value your own time, and it is priced out in full in the Runsite comparison of Coolify against a managed platform.

Do the portability work before you choose a destination, because all of it is useful regardless of where you end up. Write a Dockerfile and confirm the image builds and runs locally, which turns a platform-detected application into one you own. Flatten the environment: as of writing, Railway services can reference each other's variables, so what you have is a graph of pointers rather than a list of values, and each one needs resolving into a literal while the platform is still there to tell you what it meant. Take a database dump and actually restore it somewhere, since an untested dump is a hypothesis rather than a backup. Move anything on an attached volume into object storage, which is the least portable thing you own. Then deploy once from a clean clone to find the manual steps you have forgotten you perform. After that the move itself is mostly the database, and the schedule should be planned backwards from how long the restore takes.

Yes, and it is a different question from whether a platform offers a European region. Clever Cloud, Scalingo, Upsun and Runsite are examples of platforms whose operating company is itself established in the EU, which is the property that determines whose law applies to your customers' data. Railway is a US company as of writing, and so are most of the platforms that appear in alternatives listicles, which means moving between them changes your billing model and leaves the jurisdiction question exactly where it was, whichever region you deploy into. Two checks separate the two situations: which legal entity appears in the terms you are agreeing to and where it is registered, and who the subprocessors are and where they sit. Both live in the terms or the DPA, not on the pricing page. The fuller version of that test, including the three different things "European" is used to mean, is in the Runsite guide to choosing a European Heroku alternative.

Your app deserves to be online

Free to start. Deploy in under a minute. No credit card needed.