Two platforms now bet their zero-config build story on Railpack — Railway, which built it, and Coolify, which just shipped it as a first-class build option in v4.1. Nixpacks, the tool that defined auto-detected builds for half a decade, is frozen in maintenance mode with no Node 24 support. And the Cloud Native Buildpacks spec, for all its CNCF maturity, was not the thing either platform reached for. That is what consolidation looks like: not an announcement, but a second adopter making the same choice for the same reasons.
The numbers behind the verdict: Railpack produces images 38% smaller for Node and 77% smaller for Python than Nixpacks, resolves exact major.minor.patch versions Nix's commit-pinned packages could never express, and locks dependencies on every successful build so a default-version bump upstream can never silently break your deploy. If you run a self-hosted git-push fleet, the question is no longer whether Nixpacks is done — Railway's own maintainer said it plainly: "We are deprecating nixpacks and replacing it with railpack." The question is whether your build-detection story tracks Railpack directly. This post argues it should.
What shipped in v4.1: Coolify v4.1.0 landed in May 2026, roughly two weeks after v4.0 went stable in April following about two years in beta. The headline for builders is Railpack as a new build-pack option — selectable where Nixpacks, Dockerfile, Docker Compose, and Static already live — with build-time environment variables and multi-stage build support. It arrived alongside structured audit logging for API and auth events and a stability update to the official instance-level MCP server. "First-class" here means a supported dropdown option, not a plugin hack; "beta" means the option is new and still hardening, which is exactly why watching it now pays off later.
Why Railway walked away from Nix
Railpack was announced in March 2025 in a post titled "Why We're Moving on From Nix," and the reasoning is worth revisiting because every failure mode it names is one a self-hosted operator inherits by staying on Nixpacks. Railway had built over 14 million apps with Nixpacks. It worked for roughly 80% of users — which still left around 200,000 people hitting its limits regularly. Scaling from 1 million users toward 100 million needed a new builder, not a better Nix abstraction.
The first failure mode was versioning. Nix ties package versions to commits in the nixpkgs repo, and only the latest major version of each package is reliably available. Railway's workaround was a hand-maintained table mapping version strings to commit SHAs — and because every version rode on one shared commit hash, bumping the hash to support a new package version moved every other package version with it. A default-version change upstream could break previously green builds with no change on the user's side. For Node and Python, the team effectively gave up and supported only the latest major. That is the mechanism behind today's most visible symptom: Nixpacks has no Node 24 support and never will, because nobody is home to re-pin the table.
The second failure mode was image size. Nixpacks pulled build-time and runtime dependencies alike into a single /nix/store layer with no way to split them. The final image carried the compiler toolchain to production. The third was caching: Railway injects a deployment ID into every build, and any layer after that injection could never hit cache — Nixpacks gave the team almost no control over when invalidation happened. Three structural problems, all downstream of one decision: abstracting away the parts of Nix that make Nix what it is "just fundamentally doesn't work," in the announcement's words.
What Railpack actually is
Railpack keeps the zero-config promise — push code, get an image — and replaces everything underneath. The codebase moved from Rust to Go for the BuildKit libraries. Instead of emitting a Dockerfile, Railpack generates a custom BuildKit LLB graph plus a BuildKit frontend, giving it precise control over each layer, each input, and how the final filesystem is assembled. The pipeline splits into three phases: Analyze (inspect the code, decide packages, commands, and start command), Plan (emit a JSON-serializable build plan of steps with explicit inputs), and Generate (turn the plan into an LLB graph and solve it, highly parallel, cache-aware).
Two design choices matter most for operators. First, version resolution runs through Mise, so engines.node and friends resolve to exact patch versions instead of approximate Nix commits — the commit SHA table is gone. Second, Railpack locks the dependencies of every successful build, so updating a platform default from Node 22 to 24 cannot retroactively break your service. Cache invalidation is handled by hashing the used variable values and mounting the hash into an input filesystem: same code plus same variables means a cache hit, even with per-deploy IDs in play. Secrets travel through BuildKit secrets, keeping them out of logs and the final image.
There is one migration gotcha to know before you flip anything: under Railpack, nixpacks.toml is silently ignored. Railway made Railpack the default for new services in spring 2026, and the config surface is now railpack.json (or builder = "RAILPACK" / "NIXPACKS" in railway.toml to pin either side explicitly). Teams migrating report the classic symptom — a deploy that worked yesterday failing with "Error creating build plan" — fixed by moving install and build commands into the new file. Silent config drift is the tax on every builder migration; budget an hour to audit yours.
The comparison: Nixpacks vs Railpack vs Cloud Native Buildpacks vs Dockerfile
Here is the layer as it stands in 2026, across the dimensions that actually decide a fleet's default:
| Dimension | Nixpacks | Railpack | CNB (Paketo / Heroku) | Dockerfile |
|---|---|---|---|---|
| Auto-detection | Excellent, broad language coverage | Excellent, multi-language aware (Python+Node monorepos included) | Good via detect/build lifecycle, narrower happy path | None — you write it |
| Version granularity | Approximate (Nix commit SHAs, latest majors only) | Exact major.minor.patch via Mise, locked per build | Exact via buildpack release pinning | Whatever your base image says |
| Image size | Bloated single /nix/store layer | 38% smaller (Node) to 77% smaller (Python) vs Nixpacks | Lean, rebaseable layers | As lean as your multi-stage skills |
| Caching control | Little; deploy IDs bust cache | Direct BuildKit control, sharable caches across environments | Good layer reuse + rebase without rebuild | Manual layer ordering |
| First-use weight | Single binary, fast | Single binary, fast | Builder image pull (~500MB Heroku, ~800MB Paketo) | Zero (daemon you already have) |
| Governance | Frozen: maintenance mode, deprecated by its own maintainer | Active: Railway's default, open repo, second adopter in Coolify | Most mature: CNCF project, used by Heroku and Google Cloud | Ubiquitous standard |
The honest reading of this table is that CNB wins on maturity and supply-chain features — rebaseable layers and SBOM generation are real, and compliance-heavy shops should weigh them. But maturity is not what decides a zero-config default. First-use weight, detection breadth, and who is actively extending language support decide it, and on all three Railpack now leads while Nixpacks is frozen. Dokploy's docs are a telling data point: the platform offers a Paketo build type and still recommends Nixpacks as the straightforward default. Coolify just leapt past both.
What a second adopter signals
Railway eating its own cooking proves Railpack works for Railway. Coolify picking it up proves something bigger: the zero-config layer is consolidating around one successor rather than fragmenting into Nixpacks forks.
Consider the options Coolify's maintainers and community had. Forking Nixpacks was available — it is open source, and the detection logic is proven. Going CNB-first was available — the spec is mature and Paketo builders are a pack build away. The community even sketched the maximalist version: a third-party PRD proposed adding Railpack plus Heroku plus Paketo buildpacks as parallel options. What actually shipped in v4.1 was Railpack, as the single new zero-config path, driven by user demand — Coolify issue #7983 explicitly asked for migration off Nixpacks citing maintenance mode and the missing Node 24 support.
That choice says the market has learned what "maintenance mode" costs in this layer. A builder is not a library you can pin and forget; it has to track every language release your users deploy. An unmaintained builder rots on contact with new runtimes — Node 24 today, whatever ships next quarter after that. Betting the default on a frozen tool means every new language version becomes your team's problem. Coolify chose the builder whose roadmap still moves, and in doing so gave every smaller self-hosted fleet permission to make the same call without feeling early.
What your self-hosted fleet should do
If you operate a git-push platform on machines you own, here is the decision checklist this consolidation implies:
- Track Railpack directly for auto-detected language builds. It is the only zero-config builder with active language support, exact versioning, and locked, reproducible builds. Do not fork Nixpacks to add the Node version you need today — you will own that fork forever.
- Keep the Dockerfile escape hatch. Railpack covers the 80%+ auto-detected case; tenant Dockerfiles cover everything else. Every platform in this post — Railway, Coolify, Dokploy — keeps both, and that pairing is the actual industry standard.
- Reach for CNB/Paketo only where its strengths pay. If you need OS-layer rebasing without rebuilds, SBOMs for compliance, or Heroku-compatible buildpack behavior, Paketo earns its ~800MB first pull. Do not pay that weight as your default when detection and iteration speed are the job.
- Audit config surfaces during migration.
nixpacks.tomldoes not carry over;railpack.jsonis the new file. Grep your tenants' repos for the old filename before you switch defaults, or the "it worked yesterday" tickets will find you. - Watch Coolify v5. Multi-server scaling is the stated focus of the next major, and how Railpack builds behave across build servers will preview what your own fleet needs if you outgrow one box.
The broader lesson is about where PaaS leverage comes from in 2026. The build layer spent years split between Heroku-style buildpacks, Nix-backed auto-detection, and hand-rolled Dockerfiles. Railway's 14-million-build education, compressed into a BuildKit-native successor and now validated by an independent second platform, has effectively settled the auto-detected branch of that split. Your fleet gets to inherit the answer instead of re-running the experiment.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.



