Mike Hergaarden — M2H founder, co-creator of Photon Unity Networking — wrote one backend in 2016 so he could see what was happening inside Marooners after it left his hands for PlayStation, Xbox and PC. Ten years later every game the studio shipped talks to that same system: Marooners, Verdun, Tannenberg, Isonzo, Crash Drive 2 and 3, plus another studio’s game this year. Seven games, eleven platforms, about 20,000 lines of PHP on Google App Engine with Firestore, and a hosting bill of 10 to 50 euros a month for all of it. This month it was replaced by a C# version on Cloud Run — with the URLs and the JSON unchanged, because a Switch build from 2021 will never be patched and must not notice.

The decisions he would make again:

  • Alert on the rate, not the count. The crash alert fires on exceptions per active user (threshold 0.05) or errors per session, not on raw totals. On launch day that means thousands of players before anything triggers; two years later, at a few hundred concurrent, the same rule still catches a broken patch within the hour. Never retuned.
  • Buckets, not events. Firestore has no joins and bills per read and write, so the client batches analytics and the server aggregates them into hourly and daily rows. A dashboard for a game with thousands of daily players costs a few hundred reads instead of millions of writes.
  • Three crons for every job. Each scheduled job is registered three times, at minute 00, 01 and 02, and picks the games whose index matches its minute modulo three. One cron walking every game would spike load hourly; three small ones need no queue or scheduler.
  • Five attempts to repair broken JSON. Control characters in stack traces, invalid UTF-8 in device names, Windows backslashes, parental filters that rewrite the request body, and countries where connections are intercepted — Iran being the most memorable. Each successful repair tells him which strategy fired, so he debugs production without touching a player’s machine.
  • The cracked build that poisoned the logs. A pirated Crash Drive 3 flooded the exception reports by crashing in a loop. One remote-config line — ignore PC builds below version 5000 — fixed it in five minutes. The same version checks turned out to be a cheap way to spot trainers and cheat builds.
  • Cheaters banned on context. The auth call carries playtime, currency, unlocked items and purchases, and compares them against what is physically possible: under an hour of playtime with every car unlocked is an instant ban. The server assumes every client can lie; the global counters can only go up.
  • Milestones that scale with the game. Discord pings every 10 sales under 100 owners, every 100 under 1,000, every 5,000 under 100,000, then every 100,000. The whole team watches the first hundred sales land one at a time, and a year later nobody is being spammed.
  • One abstract module per platform. Eleven modules against eleven platforms in the Unity layer, so game code calls the same unlock or save function everywhere and never references a console SDK.
  • Kill complexity that is not yours. He threw out a Piwik-plus-Redis setup early because debugging someone else’s architecture was blocking shipping. The API root is still api_v1, because the day backwards compatibility became impossible never came.

What stands out is how little of it is clever. The stack is schemaless, the counters only increment, the crons are redundant by design, and the alert is a ratio rather than a total. Those constraints are why the bill follows the player count and why the thing survived a change of owner: BlackMill Games still runs the WW1 titles on it, and when they built a new game this year they kept it instead of replacing it. A backend that outlives the studio that made most of its games is doing something right — and it is the part of gamedev nobody writes a postmortem about, which is exactly why this one is worth reading.