Turn a SQL Server into a city you can walk through. SQLSimCity is a self-hosted, read-only performance tool that draws your instance as an atlas of databases and each database as a city — tables are buildings sized by real page counts, query traffic is roads, and waits are lanes leading to civic facilities like the Lock Authority and Memory Grant Office.
Every shape maps to a measurement you can verify. Nothing is invented, and unavailable evidence is drawn as a wireframe rather than a guess.
Try the live demo → · Heavily inspired by PGSimCity.
- Server atlas — every database on the instance as its own city, plot sized by allocated storage and tallest tower by used storage.
- Database city — tables and indexes as buildings, query families as roads, Query Store waits as lanes into tempdb, log, lock, memory-grant, CPU, and I/O facilities.
- Two views of the same city — a flat top-down map for reading structure and traffic, and a 3D city for reading massing. One toggle, one object graph, the same evidence.
- Live query feed — queries scroll past as they run, and each one sends a vehicle down the route its plan actually takes, leaving a light trail that fades. Clicking a query pins its route and its evidence, the same as clicking a query family.
- The city directory — one searchable sidebar region listing query families, tables, and infrastructure together, each with its measured metric and its block address on the map. It is a live document: entries arrive, move, and drop out as the retention window advances, and traffic colour is graded from the last few minutes rather than the whole history.
- Incident pins — live blocking and wait-graph cycles pinned to the building they were measured on, with the source DMV and observation time in the popup.
- Offline archives and an optional outward-only edge connector for servers you can't reach directly.
Building placement is deterministic: every lot is derived from a seeded generator keyed on the database's own id, so the same database lays out identically on every load and every machine, and loading another page of objects never moves a building that is already on screen.
SQLSimCity is strictly read-only against monitored servers. Query Store history is aggregate evidence, live DMVs are point-in-time samples, and inferred relationships are always labelled with their confidence. A subsystem that could not be sampled is drawn as unavailable, never as clear.
Warning
SQLSimCity has no built-in login. Anyone who can reach the page sees all evidence. Keep it on loopback or a trusted network, or put it behind an authenticating reverse proxy. See SECURITY.md.
Point it at a SQL Server and it draws that server. One connection string is the whole configuration — setting it turns connected mode on by itself.
docker run --rm --name sqlsimcity `
--publish 127.0.0.1:8080:8080 `
--volume sqlsimcity-data:/data `
--env ConnectionStrings__SqlSimCity="Server=sql01.example.internal,1433;Database=master;User Id=sqlsimcity_reader;Password=<password>;TrustServerCertificate=true" `
ghcr.io/cbattlegear/sqlsimcity:latestOpen http://127.0.0.1:8080. The atlas appears immediately and each database fills in as it is measured; Query Store history keeps building for a few minutes after that.
A few notes on that command:
- A password containing
;or=must be quoted. WritePassword='p;a=ss', single quotes and all, or the value splits into fragments and the string will not parse. A connection string that fails to parse stops startup with a deliberately value-free error, so it never quotes your password back into a log. TrustServerCertificate=trueis for self-signed development certificates. Drop it against a server whose certificate you trust. TLS itself is never optional:Encrypt=falseis rejected.--volume sqlsimcity-data:/datais what makes history survive a restart. Connected Query Store history is written there, and without a volume every restart starts the city from an empty window. Captured query text and plan XML are stored in the clear — see SECURITY.md.masteris only the connection's initial catalog. SQLSimCity enumerates the server from there; it does not restrict collection to that database. On Azure SQL Database, which cannot enumerate its siblings, name the database you want instead.:latestis for trying it out. A real deployment should pin the manifest digest, which is what makes a rollback and a signature check possible — see operations.
The password is read into a SqlCredential and never lands in a log or a diagnostic, but an
environment variable is still readable by anything that can read the process environment, and it
cannot be rotated without a restart. For production, set the connection fields individually and
mount the password as a read-only file secret — see connected mode for
the hardened setup, least-privilege permissions, Azure SQL, Query Store, and live sampling.
Fixture mode draws a synthetic city from the sanitized evidence in fixtures/, with no server and
no connection string.
docker compose up --buildOpen http://127.0.0.1:8080.
| Flat map view | Server atlas |
|---|---|
![]() |
![]() |
Both surfaces are the same map shell: a full-screen map, a searchable sidebar, and one toggle between the flat map and the 3D city. The tile at the bottom-left of the map switches between them.
| Guide | Contents |
|---|---|
| Architecture and evidence | Components, evidence boundaries, visual semantics, scale, and API surfaces |
| Connected mode | SQL connection profiles, permissions, Query Store, live incidents, TLS, and secrets |
| Operations | Reverse proxy and AllowedHosts, backup/restore, upgrades, rollback, SBOM, and provenance |
| Security | Threat model, key rotation, Kerberos, Microsoft Entra ID, and fail-closed behavior |
| Offline archives | Redacted export format and offline import |
| Edge connector | Outward-only remote collection, signing, replay defense, and encrypted spool |
| SQL probe catalog | Read-only probe contracts, permissions, platform scope, and units |
| Fixture contract | Sanitized deterministic evidence used by tests and demos |
Requires .NET SDK 10 and Node.js 24 (Node 22.12+ also works). Vite serves the UI and proxies API/SignalR traffic to port 5080.
# Terminal 1
dotnet run --project src\SqlSimCity.Api --urls http://127.0.0.1:5080
# Terminal 2
Set-Location web
npm install
npm run devFull validation:
npm test
node --test fixtures\v1\test\validate-fixtures.test.mjs
dotnet test SqlSimCity.slnx
Set-Location web
npm test; npm run typecheck; npm run buildPer-release notes are on the Releases page; CHANGELOG.md carries the breaking changes and the long-form development record.
SQLSimCity is independent software. It is not affiliated with, sponsored by, or endorsed by Microsoft, Electronic Arts, Maxis, the SimCity franchise, or the PostgreSQL project. No SimCity assets are included.
Copyright 2026 SQLSimCity contributors. Licensed under Apache-2.0; see LICENSE and NOTICE.


