all posts

Northflank vs Railway: Control or Momentum?

Ajay Kumar··11 min read

If you are comparing Northflank and Railway, you have already made the interesting decision. You decided you are not going to operate Kubernetes yourself. Everything after that is a question of taste, team shape, and how much of the machinery you want visible — and the honest answer is that both of these platforms are good at the thing they both do. Most of the internet's "X vs Y" content needs one of the two to be bad. Neither of these is bad. They are shaped differently, and shape is what you are actually shopping for.

I'm Ajay. I built PandaStack, a Firecracker microVM platform, which puts me adjacent to this category rather than in the middle of it — we do app hosting too, but our reason for existing is isolation, not breadth. I'll declare that properly near the end, in one clearly labelled section you are welcome to skip. The rest is written for someone deciding between these two, not for someone I'm trying to talk out of it.

Read this as a description of product philosophy, not a feature table. Both platforms ship constantly: features, regions, plan structures, and limits all move, and any specific number I printed here would be wrong within a quarter. I am deliberately quoting no prices, tiers, quotas, or benchmark figures for either vendor. Before you commit architecture or budget, verify everything against their current docs and pricing pages — and where I characterize either product below, treat it as a starting hypothesis to check, not a fact to build on.

The shared premise: git push, then a URL

Strip the branding and both platforms answer the same question, which is the most common infrastructure question there is. You have a repo. It probably needs a database. It almost certainly has a background worker or two — a queue consumer, a nightly job that emails someone a CSV. You do not want to run a cluster, write Helm charts, or become the person who understands the ingress controller. You want a push to a branch to end with a running thing that has a URL and does not fall over.

That premise is worth stating plainly, because it is why the comparison is hard: both platforms genuinely solve it. Both will take a repo, build it, run it, hand you a hostname, attach a Postgres, keep a worker alive, and show you logs. Hand the same small web app to two teams and tell one to use each, and both are deployed by lunch. Anyone telling you one of them can't do the basics is selling something — possibly the other one.

So the real question is not capability. It is which set of defaults you want to live inside for the next two years, and which way the platform leans when your needs get weird — because they will. Every application eventually grows a job that runs at 03:00, a service that must not be publicly reachable, and a conversation about where the data physically sits.

Railway's shape: get the thing running now

Railway's center of gravity is developer experience. The product is built around making the distance between "I have a repo" and "there is a URL" as short as it can reasonably be, and it is unapologetic about optimizing for that first impression. Connect a repo, let it work out how to build the thing, and you get a deploy. Datastores are first-class add-ons rather than a separate ceremony — you attach a Postgres or a Redis, and the connection details wire themselves into your services' environment rather than being copy-pasted at 1am.

The most distinctive piece is the visual model. Railway shows your project as a canvas of services and the connections between them, which sounds cosmetic until you onboard a new engineer. "Here is the picture of our system" is an underrated artifact, and most infrastructure tooling makes you reconstruct it from YAML in your head. Templates extend the same instinct: a one-click path to a working instance of some common thing.

The philosophy underneath is ergonomics-first: defaults are chosen so the common case needs no configuration, and the platform will make decisions on your behalf to keep momentum. That is a real product position, not a shortcut. The trade is the one every convenience layer makes — when you are the common case it feels like magic, and when you are not, you spend your energy overriding a decision you did not know was being made. Most apps are more ordinary than their authors believe.

Northflank's shape: a platform team you didn't have to hire

Northflank's center of gravity sits a notch closer to the infrastructure, and the vocabulary gives it away: build pipelines, jobs, crons, addons, environments. It expects you to have opinions and gives you places to put them — heavier on day one, lighter on day four hundred, when the thing you need to change is a build argument rather than a whole deployment model.

Two emphases stand out. The first is builds: the pipeline is a first-class configurable object rather than an implementation detail on the way to a container, which matters most when your build is genuinely non-trivial — the monorepo with six deployable services and a shared package, the app with a native dependency that needs a specific base image. The second is bring-your-own-cloud: running the control plane against your own cloud account, so workloads execute on infrastructure you own and pay for directly.

BYOC is not a feature in the way "supports cron" is a feature. It is a different product decision, and it changes who you are as a customer. Data residency stops being a support ticket and becomes a region you chose, compute lands on a bill you already negotiate, and your security review gets an easy answer to "where does customer data live." The cost is that you now own a cloud account with real things in it. If you have ever pushed a fully-hosted PaaS through procurement at a company with a serious compliance function, you already know why some teams will pay for this option without reading any other page on the site.

A useful heuristic: Railway optimizes the first hour, Northflank optimizes the second year. Both statements are compliments. If your bottleneck right now is shipping at all, the first hour is worth more than the second year — and if your bottleneck is a platform team you can't afford to staff, it is the other way round. Confirm the current shape of both against their docs; this is a philosophy read, not a spec sheet.

The dimensions that actually decide it

Written qualitatively on purpose, because the shapes below are stable and the specifics under them are not. Check every line against current documentation before you treat it as a decision input.

  • Positioning — Northflank: an infrastructure-shaped platform for teams who want platform-team control without staffing one. Railway: an ergonomics-first platform built around making deployment feel effortless.
  • Time to first deploy — Northflank: fast, but it asks a few more questions on the way, because it assumes you want to answer them. Railway: optimized hard for this specific moment, as a deliberate product priority.
  • Build pipeline control — Northflank: builds are an explicit, configurable object, which is much of the point for monorepos and non-trivial builds. Railway: automatic detection with escape hatches; the happy path is designed to need no configuration at all.
  • Jobs and cron — Northflank: prominent first-class primitives, described in the product's own vocabulary. Railway: supported as part of the service model; check the current docs for exactly how scheduled and one-off work is expressed today.
  • Managed datastores — Northflank: addons alongside the rest of the platform machinery. Railway: first-class add-ons wired into the service graph with connection details propagated for you. For both, ask about backups, restore, and version upgrades before trusting either with production state.
  • Preview environments — Northflank: environment and pipeline concepts built for exactly this. Railway: per-branch ephemeral environments as a natural extension of the project model. Verify current behaviour on both; this area moves fast.
  • BYOC and self-hosting — Northflank: offers running on your own cloud account, which is a genuinely different product decision and the strongest single differentiator here. Railway: fully hosted; you are buying a managed service, not a control plane for your account.
  • Networking — Northflank: more explicit surface for private service-to-service connectivity and network configuration. Railway: private networking between services in a project, presented in the same connected-graph model as everything else.
  • Team and RBAC — Northflank: leans to the granular, organization-shaped end, consistent with its platform-team framing. Railway: team features exist and keep improving. If fine-grained access control is a hard requirement, make both show you the current model in writing.
  • Untrusted-code fit — Northflank: not designed for it. Railway: not designed for it. Neither markets itself as a hostile-code sandbox, and that is a correct scope decision by both rather than a flaw — see the isolation section below.

The lock-in nobody writes about

Here is the part every comparison post skips, which is unfortunate, because it is the part that costs money later. What binds you to a PaaS is not the deploy button — deploy buttons are interchangeable. Four things bind you, in roughly ascending order of pain.

  1. The managed database. It holds the state, it has the backups, and it is the only component where "just move it" involves downtime and a rehearsal.
  2. The environment-variable graph. Not the values — the wiring. Which service reads which secret, which connection string is injected by the platform, and which of those only exists because a UI generated it.
  3. The private networking topology. Service A talks to service B over a private address that the platform invented. That address does not exist anywhere else, and neither does the assumption baked into your code that it will resolve.
  4. The build configuration that lives only in their UI. This is the quiet one. If the knowledge of how your app is built exists as a set of form fields in someone's dashboard, then your build is not reproducible, and a migration turns into an archaeology project conducted under deadline.

The fix for the fourth is cheap, and worth doing whichever platform you pick: keep the build reproducible outside the platform. A Dockerfile in the repo is the least glamorous and most durable portability insurance in this industry, and it is the common denominator between these two platforms and roughly everywhere else you might run the thing later.

# Portability insurance: the build lives in the repo, not in a dashboard.
# If this works on your laptop, it works anywhere either platform can run it.

docker build -t myapp:local .
docker run --rm -p 8080:8080 --env-file .env.local myapp:local

# The app must come up with ONLY the env vars you can enumerate.
curl -fsS localhost:8080/healthz && echo "starts the same everywhere"

# Two things worth proving on a quiet afternoon:
docker build --no-cache -t myapp:clean .        # no hidden cache dependency
git ls-files | grep -q '^Dockerfile' || echo 'build spec is not in the repo - fix that first'

# And write the env graph down where humans can read it.
grep -rhoE '\bprocess\.env\.[A-Z0-9_]+|os\.environ\[[^]]+\]' src/ | sort -u

The database is the other one, and it deserves an actual drill rather than an intention. Everyone believes they can export their production database. Very few people have watched themselves do it, timed it, and then restored it somewhere else and run the app against the result. Do it once, on a boring Tuesday, before it is an incident.

# The portability drill. Run it once now, not during an outage.
export SRC_URL="postgres://user:pass@host:5432/appdb?sslmode=require"
STAMP=$(date +%Y%m%d)

# 1. Export. Time it. That number is part of your migration plan.
time pg_dump --format=custom --no-owner --no-privileges \
  --file="appdb-$STAMP.dump" "$SRC_URL"

# 2. Restore into a throwaway Postgres you control.
docker run -d --name pgdrill -e POSTGRES_PASSWORD=drill -p 5433:5432 postgres:16
sleep 5
DST_URL="postgres://postgres:drill@localhost:5433/postgres"
psql "$DST_URL" -c 'create database appdb;'

pg_restore --no-owner --no-privileges --jobs=4 \
  --dbname="postgres://postgres:drill@localhost:5433/appdb" "appdb-$STAMP.dump"

# 3. The step people skip: point the app at the restored copy and use it.
psql "postgres://postgres:drill@localhost:5433/appdb" \
  -c 'select count(*) from users;' \
  -c 'select extname from pg_extension order by 1;'

That last query is not decoration. Extensions are where database migrations go to die: a platform-managed Postgres may have things enabled that your target does not offer, and you would rather learn that from a drill than from a rollback. Ask both vendors in writing what your export path is, whether you can take a logical dump on demand, and what happens to your data if you stop paying. A vendor who answers cheerfully is telling you something good about themselves.

The isolation question: both are container platforms, and that's correct

This is a scope point, not a criticism. Both of these are container platforms, and for running your own code that is exactly the right answer: containers are fast, cheap, dense, and surrounded by decades of accumulated operational competence. Nothing below is a knock on either product.

But a container is a shared-kernel boundary. Your process and every other process on that host are talking to the same kernel, and the isolation is a set of namespaces and cgroups asking politely that everyone stay in their lane. That is a fine boundary between your services, which are all equally trusted because you wrote all of them. It is a completely different proposition as a boundary against code that is actively trying to get out. A container is, at the end of the day, a strongly-worded suggestion to a kernel you are sharing with strangers.

So here is the failure mode I actually see, and it is nobody's fault: you build an app on one of these platforms, it goes well, and then the product grows a feature that runs code your users wrote — a plugin system, a formula language, a notebook, or the 2026 classic, a feature where a model writes code and something has to execute it. The path of least resistance is to run it where the app already lives. Please don't. Neither vendor markets itself as a hostile-code sandbox, neither is asking for that job, and the fact that your app lives there is not an argument that arbitrary code should too.

The correct move is to keep the app where it is and put the untrusted execution behind a boundary designed for hostility: hardware virtualization, a separate guest kernel, and a lifecycle that ends with the whole environment destroyed rather than cleaned. That is a different product category, and treating it as one is how you avoid the awkward conversation later.

Where PandaStack fits (this is the part where I'm biased)

Declaring the interest plainly: PandaStack is mine, and it exists for the isolation problem above. Every sandbox is a Firecracker microVM with its own guest kernel under hardware virtualization, not a namespaced process. Creates go through snapshot restore rather than a boot — p50 179ms and p99 203ms end to end, with the restore step itself around 49ms; only a template's very first spawn does a real cold boot, roughly 3 seconds. You can fork a warmed sandbox with copy-on-write memory and disk in 400-750ms on the same host, which is what makes branching an environment cheap. We also run managed Postgres on microVMs with branching and point-in-time recovery, and git-driven app hosting with scale-to-zero on the same substrate.

from pandastack import Sandbox

# Your app stays on whichever PaaS you picked. The code your users -
# or a model - just wrote goes somewhere with a kernel of its own.
def run_untrusted(source: str) -> dict:
    with Sandbox.create(template="code-interpreter", ttl_seconds=300) as sbx:
        sbx.filesystem.write("/work/snippet.py", source)

        run = sbx.exec("cd /work && python3 snippet.py", timeout_seconds=60)
        if run.exit_code != 0:
            return {"ok": False, "stderr": run.stderr[-2000:]}

        # Only the artifact crosses back into your trusted process.
        return {"ok": True, "report": sbx.filesystem.read("/work/out/report.md")}

# ttl_seconds is the dead-man's switch: your orchestrator will eventually
# crash between create and cleanup, and the VM still has to die.

Now the part I would want to read if I were you. If what you need is a broad PaaS — a mature marketplace of one-click datastores, years of accumulated team-management features, the long tail of integrations a general-purpose platform accretes — Northflank and Railway are further along that road than we are, and it would be silly to pretend otherwise.

And picking a platform for isolation you do not need is a bad trade: if everything you run is code your own team wrote and reviewed, a hardware boundary buys you nothing you can spend, and you paid for it in breadth. My pitch is narrow on purpose — use a PaaS for the app, use us for the untrusted tier, and be suspicious of anyone claiming one product answers both questions.

Pick Railway if / pick Northflank if / pick neither if

  1. Pick Railway if your bottleneck is shipping, your app is an ordinary web service with a database and a worker or two, and you would rather spend this week on product than on build configuration. The visual service graph is a real onboarding asset for a small team that will grow.
  2. Pick Northflank if your build is non-trivial, you have real opinions about pipelines, jobs, and networking, or - decisively - if running on your own cloud account matters for cost, data residency, or a compliance review. BYOC is the single clearest reason to choose one of these over the other.
  3. Pick either, honestly, if you are a two-person team with a Rails or Next app and a Postgres. Spend the deliberation budget on your Dockerfile and your export drill instead; those transfer, and the platform choice matters less than you think at this size.
  4. Pick neither if your requirement is running code you did not write - user plugins, model-generated scripts, customer-submitted jobs - because that is a sandboxing problem with an isolation-boundary requirement, and both of these are container platforms by design. Also pick neither if you genuinely want raw Kubernetes with your own operators, in which case you have talked yourself out of the premise of this post.
  5. Whichever you pick: keep the build reproducible in the repo, know your database export path before you need it, and write down the environment-variable graph while you still remember why each one exists.

One last thing: run a real service on both for a week before deciding, and make it the annoying one rather than the hello-world one - the service with the native dependency, the migration step, and the cron job nobody documented. Comparison posts, this one included, are how you form a hypothesis. A week of your actual app is the experiment.

Frequently asked questions

Is Northflank or Railway better for a small team?

For a small team shipping an ordinary web app with a database and a background worker, Railway's ergonomics-first posture usually gets you productive faster, and its visual model of services and their connections is a real onboarding asset. Northflank tends to pay off later, when your build is non-trivial or you need the control a platform team would otherwise give you. Neither choice is a mistake at small scale. The deciding factor is usually whether you have strong opinions about builds, jobs, and networking yet — and whether running on your own cloud account matters. Verify both against their current docs and pricing before committing.

What is BYOC and why does it matter when choosing a PaaS?

Bring-your-own-cloud means the platform's control plane orchestrates workloads that actually run in your own cloud account rather than on the vendor's infrastructure. It matters for three practical reasons: data residency becomes a region you chose rather than a support ticket, compute lands on a cloud bill you already negotiate, and security reviews get much easier because customer data stays in your account. Northflank offers this option and Railway is a fully hosted service, which is the clearest structural difference between them. The cost is that you now own a cloud account with real infrastructure in it, and the operational responsibility that implies.

Can I run untrusted or AI-generated code on Northflank or Railway?

You shouldn't, and neither vendor markets itself as a hostile-code sandbox — that is a correct scope decision on their part rather than a shortcoming. Both are container platforms, and a container is a shared-kernel boundary: namespaces and cgroups are an excellent boundary between services you wrote and trust, and a much weaker one against code actively trying to escape. If your product grows a plugin system, a notebook, or a feature where a model writes code that must execute, keep the app where it is and put that execution behind a hardware virtualization boundary with its own guest kernel and a destroy-on-finish lifecycle.

How hard is it to migrate off a PaaS later?

Easier than people fear if you prepare, and brutal if you don't. The deploy button is not what binds you — four things are: the managed database, the environment-variable graph, the private networking topology, and any build configuration that exists only as form fields in a dashboard. Two cheap mitigations cover most of it. Keep a Dockerfile or an explicit build spec in the repo so your build is reproducible outside the platform, and run a database export-and-restore drill once, on a quiet day, timing it and actually pointing the app at the restored copy. Check extensions during that drill; they are a common migration surprise.

Does PandaStack compete with Northflank and Railway?

Only partially, and I'd rather be straight about it since PandaStack is mine. We do git-driven app hosting with scale-to-zero, but our reason for existing is isolation: every workload is a Firecracker microVM with its own guest kernel, created by snapshot restore at p50 179ms rather than by booting. If you want a broad PaaS with a mature marketplace of one-click datastores and years of team-management features, those two are further along that road than we are. Choosing a platform for isolation you don't need is a bad trade. Many teams run both — a PaaS for the app, microVMs for the untrusted tier.

Keep reading

Run code in a microVM in one API call.

49ms p50 cold start. Fork, snapshot, and scale to zero.

Start free
Written by Ajay Kumar, Founder, PandaStack.