08/01/2026,
Lilly HelblingThe code was messy, boundaries unclear and generally dated. My skills and standards in my craft have improved over time, that's expected and not enough of a reason to justify a rewrite.
The issue was the platform. I'll elaborate on the specifics below, but a decision needed to be made. Do I rewrite everything for the third time, abandon the project entirely, or take it seriously and try to fix it? Spoiler: I'd consider it fixed.
Every week I got an Email from Sentry with new errors and I was simply ignoring them. "Failed to fetch" or "Request cancelled" really just aren't helpful and don't communicate user impact.
I treated PokeAPI as a proper backend when I should've been treating it as a database. I couldn't distinguish between genuine logic faults and failed downstream network requests so how was I ever going to fix them?
Furthermore, I couldn't establish what my users were doing since I didn't have an analytics platform. The only feedback I could get were from my partner and I, which was fine at the start, but if I wanted to grow and build useful features I needed better insights. So before starting any work, I set up an analytics platform, took some benchmarks and let it sit for a week while I laid out a plan.
Fun fact: Singaporean bots running Chrome on Windows 7 really like it!
I started by laying out my current pain points:
That felt like a lot, but a common architecture pattern started to look appealing. I needed a proper backend.
The frontend was no longer a cool bit of tech that I could play around with, but it became a liability. A new backend was going to transform PokeAPI data into simple-to-work-with data, so that the frontend could consume it without any modifications.
The frontend had to stop talking to PokeAPI and Pocketbase entirely - everything should be managed by the backend.
I wasn't going to compromise on type safety. The backend should output an OpenAPI schema and treat it like a product in its own right; the frontend would derive all its types from this spec.
Most importantly: No new features were to be added yet as a strong foundation will make new developments easier in the future. Achieving parity first will also re-surface any hacks that were introduced in the past and allow me to deal with them properly. In the meantime, a notebook can keep me company.
I addressed countless bugs, half of them I wasn't even aware of. Page by page, performance improved. I could re-consider my data fetching approach and expand my caching toolset: Redis.
Under the old architecture, cache could only exist in Cloudflare, or the client. The site would become faster, the further each client explored it - but there is no joy in exploring slow sites... Introducing a Redis cache between my new API (on a single server) and PokeAPI meant that every user contributed to the same shared cache. More users = faster site. I look forward to regretting this sentence in the future.
Redis + BullMQ also gave me a new message broker so I rebuilt and absorbed my old, over-engineered AWS solution. A weekly data scrape would also pre-warm my cache with 7 day TTLs - very handy!
Navigating from the homepage to a Pokemon now takes milliseconds instead of seconds.
Lighthouse scores for the most intensive page (a Pokémon) improved from ~72 to ~85.
A solid backend with platform agnostic documentation and APM feeding into New Relic.
Check the network tab when loading a Pokémon. No calls to PokeAPI, no calls to a Pocketbase instance, and no massive .json files anymore! I could take the Pocketbase instance off the internet entirely which just helps me sleep at night.
It's now running on Svelte 5. The migration script that they provided covered 90% of my code and debugging the remaining 10% was easily fixed in an evening.
Typescript passes! I don't know how this ever got missed, but during the initial build I incurred > 100 TS errors. They are now confidently a relic of the past.
The site remained in working order throughout the migration, and I continuously deployed to production.
Pokécompanion has been, and will continue to be my tech playground.
The only reason I rebuilt it in Svelte when it was previously an Express App was because I wanted to.
Pocketbase is only in use because it seemed like a cool open source project.
Styling? Is still a convoluted mess between component-specific CSS, some global setup, and Tailwind because I wanted to compare and contrast approaches.
Storybook was in there once, because there was a period where we used it intensely at work and I needed to upskill.
All these upgrades on their own would be an interesting tech challenge, but a huge waste of time. So what gives?
Much like my professional work, Pokecompanion is evolving. I no longer pride myself in the quality of the code alone, but the overall product. I have a better understanding of tech debt and how to utilise it, but also respect when something requires more time and thought.
With my business logic consolidated, platform agnostic type output, and a team-switch where I now work on a mobile app... I think it's time. Watch this space. A Pokécompanion app is in the works. Coming to a Google I'm not paying $100/year, thanks Apple Playstore near you in late 2026, early 2027.
The diff speaks for itself.
Update: Pokédexes are now live! Implemented approximately 3 evenings