Dev Insights Blog

Updates, tips, and stories to keep you in the loop

By: The ESI Development Team

Published: 2026-01-27

Smarter caching: when events drive invalidation

Hi all,

Today we're introducing a smarter caching system in which events (rather than time) are used to invalidate the cache. We are starting with the /characters/{character_id}/skills and /characters/{character_id}/skillqueue routes, and over the next few months more routes will be converted.

The problem with time-based invalidation

Caching is great when it works. But when the cache hit ratio is hovering around 1%, something is clearly not working as intended.

The old approach used time-based invalidation: responses were cached for a set period, and after that time elapsed, the next request would hit Tranquility again. The problem? Most data doesn't change on a schedule. A character might train skills for hours without any changes, or they might complete a skill and start a new one at any moment. Time-based invalidation means we either:

  • Refresh too often (wasting resources when nothing changed).

  • Refresh too rarely (serving stale data when something did change).

Neither option is ideal.

Event-based invalidation: a better way

Instead of guessing when data might have changed, we now invalidate the cache when events from Tranquility inform us a change has happened. When training for a skill starts or finishes, or when a skill queue changes — these events trigger cache invalidation immediately.

The results speak for themselves: our cache hit ratio jumped from 1% to over 90%. That is a massive improvement.

What this means

For us, this means significantly less load on Tranquility. Fewer unnecessary database queries, less work for the servers, better performance overall.

For you, this means faster updates when things change in-game. No more waiting for a cache to expire before seeing your latest skill completion. When a skill finishes training, the cache is invalidated right away, so your next request will get the fresh data.

HTTP caching headers

With event-based invalidation, the Expires header is no longer meaningful - the cache doesn't expire based on time anymore. We're keeping it in the response for backwards compatibility, but you shouldn't rely on it for cache behavior.

Instead, use the Cache-Control header. This is the modern, standard way to handle caching, and it's how cache behavior will be communicated going forward. And of course be mindful of the recently introduced rate limits!

Quality assurance

Just because the new cache is more aggressive, data quality is not compromised. We constantly revalidate whether the cached information is still correct in the background. If any drift is detected, the cached information is corrected, and an error report is generated for us to fix the underlying issue.

Wrapping up

This change is live now for the skills and skillqueue routes. You don't need to change anything in your applications - the API behavior and specifications remain the same, just faster and more efficient under the hood. That said, please use this opportunity to review the request/response headers and make sure they’re in line with our recommendations.

As always, we love to hear your feedback. Join us on the official EVE Online Discord server to discuss this and other ESI improvements.

Cheers,

Your friendly developers of the EVE Smart Invalidation (working title)