Skip to content
Back to Blog
July 31, 2026

Caching Strategies for Travel Data

What to cache, what not to cache, and how to invalidate in a domain where flight prices change every minute — reference data vs. volatile fares.

Caching Strategies for Travel Data
M

A cached flight price is a lie waiting to happen. The traveler sees $487. They tap "Book." The system checks the live price. It's $523. Now you have a trust problem.

This is the fundamental tension of caching in travel: the data you most want to cache (prices, availability) is the data that goes stale the fastest. And stale travel data doesn't just cause a bad user experience. It actively erodes trust. A traveler who gets burned by a stale price won't trust your prices again.

So we had to develop a nuanced caching strategy. Some data gets cached aggressively. Some data never gets cached at all. And the decision for each data type comes down to one question: what happens when this data is wrong?

Cache aggressively: reference data

Illustration for this section

Airport information changes at the pace of physical construction. A new terminal opens every few years. An airport code changes essentially never. Airline data is similarly stable. Routes change seasonally, but airline names, codes, and basic operating information are static for months at a time.

This is perfect cache material. We load airport and airline reference data into our in-memory cache on startup and refresh it on a schedule measured in hours, not seconds. When the AI agent needs to resolve "NRT" to "Narita International Airport, Tokyo," that lookup hits the cache and returns in under a millisecond.

Without caching, that same lookup would hit the database. Still fast at 2-5 milliseconds, but when you're resolving airport codes dozens of times per second across all active users, the database load adds up for zero benefit. The data hasn't changed since the last query.

The invalidation strategy for reference data is simple: time-based expiration plus event-based refresh. The cache expires every few hours. If we run a sync operation that updates airport or airline data, we also flush the relevant cache entries.

Never cache: flight prices

We do not cache flight search results. Full stop.

Flight prices change constantly. An airline's yield management system adjusts fares based on demand, time to departure, competitor pricing, and factors we can't even see. A price that was valid 60 seconds ago might be different now.

Showing a cached price creates a bait-and-switch dynamic. The traveler selects a flight based on a price, then discovers at booking time that the actual price is different. Even if the real price is lower, the experience feels deceptive. "Why did you show me a different price?"

Instead of caching, we re-validate at booking time. When the traveler decides to book a specific flight, the booking flow checks the live price against what was displayed. If the price has changed, we tell the traveler before they commit. "The fare has changed since you searched. The current price is $523. Would you like to proceed?"

This is slightly slower than serving cached results. A flight search takes 1-3 seconds because it's always a live query. But the trust trade-off is worth it. Travelers know that the price they see is the price they'll pay.

Short TTL: session data

Supporting diagram

User session data falls in the middle. Authentication tokens, rate limit counters, and in-progress conversation state change more often than reference data but are accessed so frequently that database queries for every check would be wasteful.

Session tokens get cached with a TTL slightly shorter than the token's actual expiration. Rate limit counters use sliding window algorithms that live entirely in the cache, with high write frequency and short TTLs. The counters expire naturally; there's no explicit invalidation needed.

For rate limiting specifically, the in-memory cache is the only storage. We don't persist rate limit data to the database. If the cache restarts, the counters reset. This means a cache restart briefly lifts rate limits, but the alternative (hitting the database 100 times per minute per user for rate limit checks) is worse.

Conversation context: cache within, invalidate across

AI conversation context presents an interesting caching problem. During an active conversation, the agent needs fast access to the conversation state: what the traveler has said, what the agent has responded, what tool calls are in flight, what offers have been presented.

We cache this aggressively within a conversation session. The working context lives in the cache with a TTL tied to session inactivity. If the traveler is actively chatting, the cache stays fresh. If they leave for 30 minutes, the context expires from the cache and gets reconstituted from the database if they return.

Across conversations, we don't cache. When a traveler starts a new conversation, the agent loads their profile and preferences from the database, then builds new context. Cached context from a previous conversation would be misleading because the traveler's situation may have changed (new booking, different trip, updated preferences).

The cache stampede problem

Cherry blossom season in Japan. A travel influencer posts about Tokyo. Suddenly, hundreds of people search for flights to Tokyo within minutes. Without cache (because we don't cache flight prices), each search hits the live API. That's fine from a correctness standpoint, but it's a lot of concurrent requests to an external service.

We don't cache the results, but we do deduplicate concurrent identical requests. If 50 people search for JFK to NRT on April 5th within the same 10-second window, we don't need to make 50 separate API calls. We make one, and all 50 requests share the result.

This is a request coalescing pattern, not a cache. The result lives in memory only for the duration of the concurrent requests. Once the search completes and all waiting clients receive the result, the data is discarded. The next search, even 5 seconds later, gets a fresh live query.

This gives us the cost efficiency of caching without the staleness risk. The data is always live, but we don't hammer external APIs with duplicate work.

The decision framework

When evaluating whether to cache a new data type, we ask three questions:

What's the cost of staleness? If stale data causes financial harm (wrong prices) or trust damage (misleading information), don't cache it. If stale data is imperceptible (airport name lookup), cache it.

How often is it read vs. written? High read-to-write ratios are ideal cache candidates. Airport data: read thousands of times per day, written once a month. Rate limit counters: written constantly, read constantly, but individually scoped so the write pattern works.

Can you validate at the critical moment? For flight prices, we can't cache the search, but we validate at booking time. This lets us show live data for browsing and confirm it before money changes hands. If you can add a validation step before the high-stakes action, the cache strategy for the browsing phase becomes less critical.

Travel data caching is a trust problem first and a performance problem second. Get the trust right, and then optimize for speed.


Nowah is an AI travel agent that searches and books real flights and hotels through conversation — no filters, no thirty open tabs. Plan your next trip.

Share this article

Ready to Plan with Nowah?

Bring the idea. Nowah will help turn it into a trip.

Try Nowah