See How PostgreSQL Works: A Hands-On Tour of PGSimCity

⬅️ Back to Tutorials

Open PGSimCity and in fifteen minutes you will have watched a query travel from client to commit, broken a database’s buffer pool on purpose, and seen exactly why one forgotten transaction bloats a table forever. No install, nothing to sign up for.

TLDR:

  • Open the city in any WebGL2 browser and press T for the 14-chapter guided tour.
  • Press Enter to trace a Non-HOT UPDATE in slow motion through buffers and WAL.
  • Run the Scenarios menu: Cache thrash, Checkpoint storm, The work_mem cliff, Long-running transaction.
  • Press G to walk at eye level; E operates levers; ? shows every key and color.
  • Reset anytime with R.

Prerequisites: any current browser with WebGL2. Running locally instead needs Node.js 20+ (or 22+) and npm run dev.

Step 1: Take the guided tour

Press T

The tour walks fourteen chapters following one connection from the client sky down through planning, the shared-buffers pool, WAL, checkpoints, vacuum, and replication. This is the fastest way to learn the city’s geography: postmaster, sixteen backends whose lighting is their state, the storage excavation where heap files sit as fields of 8 KiB pages.

Step 2: Trace one statement in slow motion

Press Enter → pick Non-HOT UPDATE → press , to slow playback

Watch the statement unfold as parse, rewrite, plan, execute, then follow it into the buffer pool, watch it create WAL, and wait with it at commit. Slowed to 0.1x, you can finally see what normally happens in microseconds.

Pro tip: press / (or Ctrl/Cmd+K) for the command palette. It searches every component, setting, and scenario by name, which beats hunting menus once you know what you want to see.

Step 3: Break it on purpose

Scenarios menu → Cache thrash → then Checkpoint storm

Cache thrash shrinks shared_buffers below its manual minimum so the clock sweep races and backends evict their own victims mid-read. Checkpoint storm spins up the checkpointer’s flywheel and floods the WAL district with full-page writes after each fsync shudder. These two scenarios explain most mystery latency spikes in production databases.

Step 4: Watch the three classic trade-offs

Run Long-running transaction and the xmin horizon blade sinks red: autovacuum still visits the table but reports zero removable rows while bloat continues, the cleanest demonstration anywhere of why one idle-in-transaction session hurts everything. Then run The work_mem cliff, where sorts spill to disk at 2 MiB and fit at 4 MiB without replanning. Finally set synchronous_commit to off, watch backends stop waiting in commit_wait, and read what you just traded away.

Step 5: Get on the ground

Press G → walk with WASD → press E near levers and doors

At eye level a buffer frame that looked like one tile becomes a structure over your head. E operates the autovacuum lever or the postmaster door; ? shows the full key map and the semantic color legend (WAL is amber, dirty pages red, vacuum violet); keys 1 through 8 jump between districts.

Step 6: Check the model against the real thing

The Machine section is a separate psql workbench running PGlite, real in-memory PostgreSQL compiled to WebAssembly, opt-in with one click. Plans, counters, and errors come from actual Postgres; the visible interior comes from the model, and each surface labels which is which.

Cleanup

Nothing persists in the browser; press R to reset all settings and Esc closes overlays. Locally:

rm -rf node_modules dist   # optional, after stopping the dev server

If it breaks: a blank screen means WebGL2 is missing or disabled; try current Chrome, Edge, or Firefox. Touch controls are only verified in Chrome’s mobile emulation. And remember the numbers are scaled for human eyes; the README’s “How much to trust this” section lists exactly which simplifications are deliberate.

Related TMFNK Content

Crepi il lupo! 🐺