How this site is built
Every chart on this site reads from small, precomputed JSON files, never a live database. Here's how those files get made.
Where the data comes from
1996 to 2020 comes from data.ontario.ca as per-year CSV resources. 2021 onward comes directly from each year's page under ontario.ca/public-sector-salary-disclosure. Both sources publish the same five columns for every disclosed employee: sector, name, salary paid, taxable benefits, employer, job title, and the calendar year. Inflation adjustment uses Statistics Canada's Consumer Price Index series (table 18-10-0005-01).
From 600MB of CSV to a few megabytes of JSON
All 30 years load into a local DuckDB database and collapse into a normalized star schema: one table of roughly 5 million salary rows, plus small lookup tables for employers and job titles. Every chart on this site is a precomputed aggregate exported from that schema, a median by sector by year, a histogram bin, a top-earners list, never a query against raw rows at request time. That's a deliberate split: charts need aggregates and must stay fast and free to host; the separate name search on this site (see the employees page) is the only part of this project that touches a real database, because it's a genuinely different problem with genuinely different scaling needs.
The hard part: the same employer, spelled differently every year
Employer names drift from year to year and file to file. "Toronto, City of", "City Of Toronto", and "TORONTO (CITY)" are the same institution, but nothing in the raw data says so. Sector names have been renamed and merged over 30 years. Some records are in French. Name casing is inconsistent throughout.
Reconciling that is a fuzzy-match pass followed by a hand-maintained override table (etl/overrides/employers.csv in the source repository) that resolves every case the automated pass gets wrong. There's no shortcut
for this part: it's the single most time-consuming step in the pipeline, and it's what makes an
"employer" page on this site mean one real institution across 30 years instead of a dozen near-duplicate
slivers of one.
What's public, and what isn't indexed
This data is public record by statute. That doesn't mean every page on this site should be a
fast, permanent Google result for someone's name: the search and individual person pages carry
a noindex tag, so this site doesn't become a name-lookup index in search results even
though the underlying data is fully public and searchable directly on this site.
Source
The full pipeline, from raw CSV to the JSON files these charts read, is open source: github.com/payamyek/ontario-sunshine-list.