Peter Wang
Home

VGCLite

Sole developer.

Competitive Pokémon team analysis, with four independent caching layers.

4
independent caching layers

server, CDN, client, module

~1k
peak weekly visitors

VGCLite pulls competitive usage data from Smogon and Pikalytics and turns it into something a player can actually build a team against. The interesting part is not the interface. It is that both upstream sources are slow, large, and update on their own schedules, and the site has to stay fast anyway.

There are four caching layers. Server-side, format discovery and Pikalytics builds go through Next's unstable_cache with explicit windows: one hour for discovery, three hours for builds, kept short because Pikalytics updates often. This survives serverless cold starts, so a Lambda waking up does not re-fetch and re-parse everything. Smogon's raw chaos JSON exceeds unstable_cache's 2MB limit, so it uses Next's fetch cache instead at six hours; PokeAPI species data sits at twenty-four, being near-static. Learnsets never change at runtime, so those live in a plain in-memory Map with no expiry at all.

Above that, the bootstrap endpoint sets a CDN policy of thirty minutes fresh with stale-while-revalidate up to a day, so the edge absorbs most traffic.

On the client, a ref-held Map is the single source of truth for every Pokémon fetched. It checks four states before making a request: fully loaded, currently loading, partially loaded, or absent. A concurrent request for a Pokémon already in flight gets the existing placeholder rather than firing a duplicate. Switching format invalidates only the usage builds in place, so sprites, stats, and types survive the switch and only what actually changed is re-fetched. A second module-level cache does the same for movepools, so reopening the build editor for a species costs nothing.

Mega formes needed a different answer. Neither source tracks them as separate entries, so the app tries a direct fetch, falls back to the base species with the item and ability force-overridden, and flags the result as approximated so the interface can label it honestly rather than presenting a guess as data.

Next.js, React, TypeScript, Tailwind CSS