---
title: "Scaling Rails isn't a caching problem: three years across Norway's biggest airports"
date: "2026-07-23"
excerpt: "Every scaling guide says caching, N+1, background jobs. Three years of scaling a real Rails system taught us the bottleneck lives somewhere else entirely."
author: "Marcin Ostrowski"
---

Search "scaling Rails application" and you'll get the same article fifteen times: add caching, fix the N+1 queries, move work to background jobs, maybe shard later. Fine advice, and it describes maybe a tenth of what scaling an actual Rails product turned out to mean. We've spent three years scaling FastTravel from one airport to every major one in Norway, and the requests-per-second part was the easy lane. This post is about the other lanes, because they're where the engineering actually went.

## "Does Rails scale" is usually the wrong worry

Founders ask this question with Twitter-folklore dread, and it deserves a calm answer: the framework will not be your bottleneck. Shopify runs Black Friday on Rails. The performance playbook is well-documented, boring, and effective, and a competent team applies it as routine maintenance rather than heroics. In three years, raw throughput never kept anyone up at night.

What multiplied instead was contexts. Every new airport meant a new physical layout, new operational rules, new fee structures, new hardware in the ground. Requests per second never made the hard-problems list. Operational surface grew like a family: each new member arrives with relatives.

## What scaling actually consisted of

The honest inventory of where three years of engineering went, ranked roughly by effort:

Tenant onboarding, again and again, until it became routine. Going from airport one to airport two forced the multi-tenant architecture ([a decision](/blog/when-should-your-rails-app-go-multi-tenant) and [a retrofit](/blog/adding-multi-tenancy-to-a-live-rails-app) I've covered separately). The work after that was making each next onboarding cheaper than the last, which is configuration design more than it is code.

Billing divergence. Per-airport fee schedules, invoicing rules, corrections, automatic passage fees billed when vehicles cross physical infrastructure. The money paths are [their own story](/blog/multi-tenant-billing-architecture), and they're where the system gets continuous engineering to this day.

The physical world. FastTravel grew from a kiosk and a simple barrier into running airport ground infrastructure: barriers that open for police, vehicles tracked by chips and cameras, active monitoring of whether the whole operation is running right. The team learned hardware integration on the job, and the lesson transfers even if your product never touches a barrier: scaling a product into new contexts means integrating with whatever already lives there, and what already lives there is never standard.

And the part that scaling guides never mention because it isn't infrastructure at all: understanding each new context before building for it. The system's first version came from Katarzyna standing at Oslo Airport watching passengers fumble and drivers idle. The result of getting that right shows up in the numbers the business actually cares about: average driver waiting times dropped from around four hours to around thirty minutes. No cache did that.

## What stayed boring on purpose

One Rails monolith, one codebase, no forks, no microservices migration. The driver app is a Rails app too, built with Hotwire Native, so web and mobile ship from the same codebase with GPS tracking where the job needs it. Every one of those choices was contrarian at some dinner party during those three years, and every one of them paid rent: a small team can hold the whole system in their heads, a change ships everywhere at once, and the operational surface we did have to grow (airports, hardware, fee schedules) wasn't competing with self-inflicted architectural surface.

That's the trade I think generalizes. You have a fixed complexity budget, and scaling spends it involuntarily on the new contexts your growth drags in, so whatever you spend voluntarily on exciting architecture comes out of the same account. The overspending check is simple to run: list what got harder this quarter, and mark which items your customers forced on you. If the self-inflicted column is winning, the budget is going to the wrong side.

## When the framework would matter

For honesty's sake: there are products where Ruby itself becomes the constraint, at traffic volumes or latency floors most products never meet. If you're routing millions of requests a second or chasing single-digit milliseconds, you're reading the wrong blog. For the rest (which is nearly everyone, including a system running ground infrastructure at every major airport in Norway), the framework question is settled by the boring playbook, and the real scaling work is waiting for you in operations, configuration, billing, and whatever your version of barriers turns out to be.

So when someone asks whether Rails scales, the three-year answer is: yes, easily, and that's the least interesting thing that will happen to you. Plan for the contexts. They're coming with relatives.
