A flight doesn’t need the same attention at 6 AM as it does 40 minutes before takeoff

A regional airline operator came to us with a problem that sounds small and isn’t: the monthly bill for their real-time data layer would not come down, and every attempt to optimize it ended in the same uncomfortable trade-off — either they overpaid, or the information reached the ramp too late.

We redesigned the system that keeps each flight’s operational data in sync and distributes it live to the tablets used by ground and onboard staff. Daily synchronization load dropped between 95% and 98.75% in the highest-volume blocks, and reads against Firebase Realtime Database fell by a factor of ~420x — without losing a single second of freshness on screen.

−98.75% in daily manifest refreshes: from 396,000 to 4,950
−95.42% in aircraft data refreshes: from 108,000 to 4,950
~420x less volume read from Firebase RTDB: from 362.88 GB to 0.864 GB per month
5x to 10x lower projected monthly cost, from a band of $800–$1000 to $80–$200

01

The problem was not volume. It was flat cadence.

The previous system treated every flight the same way, all the time. A flight departing at 22:00 was polled just as insistently at 06:00 in the morning as at 21:40, when something is actually happening. Multiplied across every eligible flight, every endpoint of the reservation system and every hour of the day, that produces hundreds of thousands of daily refreshes, of which a tiny fraction discover a real change.

It is the most expensive pattern in aviation integrations: paying for constant frequency to catch events that cluster in very narrow windows.

And it isn’t solved by simply polling less. Lowering the frequency evenly makes the operation cheaper and breaks the product: the moment the data has to be exact — door close, the last seat change, the passenger who never showed — is exactly the moment that relaxed polling arrives late.

The answer is not less frequency. It is frequency distributed where it matters.

02

First decision: adaptive cadence by operational proximity

We rebuilt synchronization as a ladder of stages anchored to each flight’s estimated time of departure. Every flight climbs that ladder on its own, according to how far it is from its operation, and each stage has its own rhythm. The principle is simple to state and surprisingly rich to calibrate: a flight’s refresh frequency should be a function of its distance to the event, not of the wall clock.

DiscoveryIndependent date buckets: yesterday every 12h, today every 2h, tomorrow every 4h
Early pre-departureSpaced-out checks, only to detect structural changes
Hot pre-departureProgressively shorter intervals as departure approaches
LiveSustained tracking, only for flights that are genuinely active
ClosedThe flight leaves the cycle. It stops costing.

The compound effect is decisive: the manifest went from 396,000 daily refreshes to 4,950, and aircraft data from 108,000 to 4,950. Not because the system looks less, but because it stopped looking where nothing was happening.

The least obvious consequence, and the most valuable operationally: data quality during the hot hour went up.

By freeing the request budget that was being spent on dormant flights, we could tighten cadence in the critical window without moving total cost upward.

The detail that changes everything: configuration to the millimeter

A ladder of stages hard-wired in code is a new problem dressed as a solution. Airline operations are not stable: they change by season, by station, by flight type, by how the reservation system behaves in a specific market. That is why every stage is configuration, not code. For each one, the following is defined independently:

The window in which it applies, expressed relative to the flight’s departure time.
The refresh interval within that window.
Which sources or endpoints are queried at that stage — not every stage needs everything.
The eligibility criteria: station, operation type, domestic or international, and any flight attribute.
The exit conditions, so that a flight leaves the cycle as soon as it stops being relevant.

That enables something worth as much in practice as the savings themselves: adjusting the synchronization policy without deploying. If a station needs more resolution in the last 30 minutes, you move a parameter. If an endpoint starts responding slowly at a specific time of day, you relax that branch alone without touching the rest. If an international route requires one additional field, you add it only where it belongs.

Optimization stops being a project and becomes a dial.

03

Second decision: use Firebase for what Firebase does best

Here was the other major drain, and it was less visible. Firebase Realtime Database is excellent at one very specific and difficult thing: distributing a state change to many subscribed devices, instantly, securely, with reconnection already solved. When a flight’s state changes, every subscribed tablet receives it by push, without anyone asking. That is exactly what a ramp operation needs.

What RTDB is not — and where cost explodes — is a query database for the backend. Billing is proportional to bytes downloaded. A server process that re-reads the flights root node in a loop to learn which flights it has to handle now is paying, over and over, to download 600 KB of data it wrote itself thirty seconds ago. In numbers: 20,160 daily reads of the main node, roughly 362.88 GB of monthly download traffic, almost entirely redundant.

The in-memory mirror

We inverted the relationship. The service keeps an in-memory mirror of flight state, hydrated with a full snapshot and refreshed every 30 minutes, while the changes the service itself produces are applied to the mirror at the same moment they are written.

Every scheduling decision —which flight enters which stage, what needs to be queried now— is resolved against local memory, in microseconds and at zero cost.
The backend stops reading Firebase and Firebase becomes an output channel: it is written when there is a real change, and that single write fans out to every subscribed device.
The security and subscription model stays intact: devices see exactly what they are supposed to see, with the same rules as always and no new intermediate layer.
Reads of the main node

20,160 / day48 / day. The root snapshot refreshes every 30 minutes; everything else lives in memory.

Monthly volume

362.88 GB0.864 GB. A factor of ~420x, with identical behavior on screen.

Every component ended up doing only what it does better than the alternative.

Process memory handles hot, high-frequency state. Firebase handles real-time distribution to N devices with delivery and security guarantees. Neither one pays the price of doing the other’s job.

04

The savings, endpoint by endpoint

Comparable base: 50 visible flights per day at one station, average departure time 12:00, 2 hours of average live tracking. The table shows the verifiable floor, not the best case.

System / data Before / day Now / day Savings
Flight manifest 396,000 4,950 −391,050 · −98.75%
Passenger detail 396,000 4,950 −391,050 · −98.75%
Special service requests (SSR) 396,000 4,950 −391,050 · −98.75%
Leg inventory 396,000 4,950 −391,050 · −98.75%
Government security information (international only) 396,000 4,950 −391,050 · −98.75%
Aircraft data (inbound) 108,000 4,950 −103,050 · −95.42%
Flight status (PSS) 14,400 up to 7,290 −7,110 · −49.4%

The flight status figure deserves an honest caveat, because it is the one we usually see reported badly in this kind of write-up: 7,290 is an upper bound, not an expected value. It assumes all 50 daily operations are consecutive departures and that each stays live for 2 hours. If some of those flights are arrivals, or if actual live time is shorter, the number drops appreciably — in mid-range scenarios it falls to 3,665 and in the tightest ones to 2,915.

There is an additional saving the table does not capture: the shape of the query changed. The old model requested broad universes per station; the new one queries a specific flight inside a bounded time window. Two requests that count the same in a table can differ by an order of magnitude in payload, latency and pressure on the source system.

05

What it means on the bill

Against a reference history of $800 to $1,000 per month, the new model projects into a far lower band. We communicate $80 – $200 as the working estimate, not the optimistic scenario: we would rather the number a committee walks away with be the one that holds under conservative assumptions.

Reference history $800 – $1,000
Conservative scenario $161.52 – $201.90
Likely scenario, high savings $81.71 – $102.14
Optimistic scenario $1.90 – $2.38

The direct saving, in any case, is the least interesting part of the outcome. What was gained alongside it:

Less pressure on the reservation system and external sources, which is where rate limits, degradations and the incidents nobody planned for tend to show up.
Better freshness in the critical window, because the request budget was reassigned to where the operation actually happens.
Room to scale station by station without cost growing linearly with the visible fleet.
An auditable synchronization policy, expressed as readable configuration instead of constants scattered through the code.

06

What we took away as principle

Three ideas we have applied since then in any real-time system with a per-operation cost.

01

Cadence is a resource, and it has to be budgeted.

It is not about refreshing more or less: it is about deciding explicitly where frequency gets spent. It is almost always badly distributed, and the redesign almost always improves cost and quality at the same time, not one at the expense of the other.

02

If a policy is going to change, it has to be configuration.

Every synchronization parameter that is hard-wired today is a future maintenance window. Externalizing them turns each adjustment from weeks into minutes, and allows calibration by station, by route and by season without touching the system.

03

Every piece of infrastructure is irreplaceable at one thing and expensive at many.

Firebase is extraordinary at distributing changes to thousands of subscribed devices. It is a poor place for a backend to go read its own state. Separating those roles required no new technology: it required seeing where the same data was being paid for twice.

07 — Let’s work together

If you are paying for constant frequency to catch events that happen in narrow windows, there is a similar case waiting in your bill.

Flyware designs and builds operational data systems for aviation: real-time synchronization, PSS integrations, and ground and onboard platforms. We start by measuring where cadence is going — and that measurement alone usually pays for the project.

Case study · Flight operations synchronization. Figures on a comparable base of 50 flights/day.