I built a 50-year simulation of NYC housing. No policy got an A.
I spent a few months building YIMBY NYC — an agent-based simulation of New York’s housing market that ticks 600 times (one per month, 2020-2070) across 55 real neighborhoods, with 10,000 household agents each standing in for 350 real households. You can play it. Toggle parking minimums, upzone the Bronx, levy a land value tax, mandate 100% affordable housing on every new project, abolish CEQR — whatever you want. Watch what happens.
I built it because I wanted to know which housing policies actually work, and I wasn’t getting clean answers from the discourse. YIMBYs say build more. Tenant advocates say protect tenants. Both are right, both are partial, and the interaction effects are where almost everything interesting lives.
After running all 48 scenarios I’d built into the simulator, here’s what I found:
No policy combination earns an A grade. Not parking elimination. Not full COYHO (“City of Yes for Housing Opportunity”). Not FAR 20 everywhere with state preemption. Not the Vienna model with 25% of the city budget going to public construction. Not even my custom “everything-yimby” combo with every supply-side reform I could think of.
The best you can do, over 50 years, is a B. And even that requires a counterintuitive mix.
Why simulate, instead of just looking at evidence?
There is no controlled experiment for housing policy. You can’t rent-control half of New York and leave the other half alone for 30 years and see what happens. The natural experiments — Cambridge after the 1994 RC repeal, San Francisco’s prop. 10, Tokyo’s permissive zoning — are individually informative but each tells you a different story about a different city at a different time, and you can read the same data either way depending on what you already believe.
What you can do is build a model. A model is not an oracle. It’s a thinking aid: an explicit description of what you believe causes what, run forward in time to surface the consequences your intuitions miss. The honest claim isn’t “this simulation predicts the future.” It’s “if these are the mechanisms, then these are the trade-offs.”
The mechanisms in this one are roughly: agents have Stone-Geary utility (housing has a subsistence floor — you can’t substitute it away for cheaper goods), they search for housing under Diamond-Mortensen-Pissarides friction (you only see a few units a month, not the whole market), they bid Alonso-Muth-Mills (commute time costs scale with wages), and they can leave for Atlanta if the city’s offer drops below a national baseline (Rosen-Roback spatial equilibrium). Developers face a real-options problem: rate volatility makes them sit on land. Landowners are sticky — they refuse to sell below their remembered peak. Community boards veto projects in proportion to local incumbent wealth.
If you’ve taken a graduate urban econ class, none of this is new. What’s new is putting it all in the same loop and watching them fight.
A cycle, not a problem
Before I show what the simulator found, look at how we got here. Every housing policy NYC has on the books is a reaction to the unintended consequences of the previous one. The simulator’s in-game history tab tells this as a 180-year cycle:
180 years of NYC housing policy
From the simulatorEvery reform created the conditions for the next crisis. Tenement overcrowding → zoning → Moses → ULURP → NIMBYs → housing shortage → COYHO.
The Tenement Era
1840s–1900sThe Birth of Zoning
1916–1961Crisis & Rent Stabilization
1963–1979Koch, Co-ops & Deregulation
1980s–1990sBloomberg Rezonings
2002–2013De Blasio & the Housing Crisis
2014–2021The YIMBY Era
2022–PresentEvery generation faces the same cycle: crisis → regulation → unintended consequences → new crisis. Tenement overcrowding led to zoning. Zoning enabled Robert Moses's clearance. Moses's destruction created community review (ULURP). ULURP empowered NIMBYs. NIMBY obstruction caused the housing shortage. The shortage drove COYHO. Can supply-side reform break the cycle?
This matters for the model because nothing in housing is born neutral. Rent stabilization (1969) is a response to vacancy decontrol’s failure. ULURP (1975) is a response to Robert Moses’s bulldozers. The Landmarks Law (1965) is a response to Penn Station. HSTPA (2019) is a response to the 1994 deregulation pipeline. COYHO (2024) is a response to the housing shortage that ULURP and HSTPA together created.
Any simulation that ignores this — that pretends 2020 NYC is a blank slate where we can just pick optimal policy — is wrong by construction. The model has to start with 55 neighborhoods carrying decades of zoning history, with ~25-65% of stock under rent stabilization, with land costs that reflect 60 years of compounding under-supply. Those are the initial conditions. The policy levers you toggle in the simulator change the next 50 years from there.
The housing-economics primer everyone skips
A lot of policy intuition starts with “rent is too high, lower it.” But rent has a structure underneath. The first thing the simulator made me really feel was the cliff:
Drag the income slider down with rent fixed. Notice the discontinuity. Below the cliff, the agent doesn’t merely shrug and accept a worse deal. The unit is infeasible: they cannot live there at any price below their subsistence floor, because food, transit, and utilities aren’t substitutable for housing. They search elsewhere. If nothing is feasible, they flee.
This is why low-income flight in housing crises looks like a regime change, not a gentle response curve. And it’s why the average rent stat lies: by the time the city’s average rent has risen 20%, the bottom 20% of earners aren’t paying it, they’re gone. The metric improves and the people get worse off.
I spent a long time on this single mechanism. It changes everything downstream. A 5% rent increase is not a “5% pinch on consumers”; for some agents it’s 5% nothing and for others it’s a 100% bankruptcy.
The supply view: necessary, insufficient, and partially captured
YIMBYism is right about something. When I ran everything-yimby — eliminate parking minimums, legalize ADUs, +20% FAR transit-oriented bonus, Universal Affordability Preference, town-center upzoning, 2% LVT, state preemption of local zoning, FAR 20 everywhere, single staircase reform, mass timber, pre-approved plans, CEQR exemption, prevailing wage repeal, lot splits — rents in 2070 land at $1,682/mo in 2025 dollars, down 62% from baseline. 2.8 million units get built over 50 years. The city expands.
That’s the best outcome in the dataset.
But here’s what stayed unfixed even in that scenario: 1 million households still ended up unhoused or fled by 2070 out of a starting demand of ~3.5M. Why?
Three reasons. First, construction has a physical limit. New buildings take roughly 36 months from proposal to delivery. The construction workforce can absorb a certain number of units per year before labor costs spike. Above the city’s labor capacity, hard costs inflate exponentially — you don’t get more apartments faster, you just pay more for each one.
Second, interest rate volatility kills development. Real Options theory: a developer with a buildable site has an option to develop or wait. In high-volatility environments, the option to wait is valuable — you might do better in a year. The model captures this with a rate_volatility term that adds to the developer’s required cap rate. When rates moved from 0% to 5% in 2022-2024 (which I burn into the timeline), proposed projects stalled even when zoning allowed them. The simulator reproduces this neatly.
Third — and this is the one that costs YIMBYism most of its premised gains:
The technical name is land value capitalization. When zoning lets you build twice as much on a lot, the lot becomes worth roughly twice as much. The new value doesn’t accrue to renters or developers. It accrues to whoever owned the land before the upzone — passively, by virtue of holding the deed.
In my model, landowners capture ~75% of the marginal value from upzoning, with a 2× cap per tick to prevent overnight repricing. Developers absorb most of the rest as higher acquisition costs. The amount that flows through to rent reductions is small.
This is why YIMBY without LVT is, structurally, a transfer program from renters and tenants of future buildings to current landowners. The supply does eventually arrive — but at much higher land cost than naive theory predicts, and the rent reductions are smaller and slower than the agitation deserves.
The fix is not to oppose upzoning. It’s to upzone and tax the windfall. Toggle the LVT checkbox in the widget above — the split shifts dramatically. In the simulation, scenarios that upzone and impose a 2-5% land value tax show much more of the surplus arriving in renters’ pockets.
The demand side: where it gets weird
If supply is necessary but partial, the obvious next move is to subsidize people who can’t afford the supply. Vouchers.
I’d expected Section 8 vouchers to be unambiguously good, in the model. They are good — for the families who get them. The simulation shows voucher recipients exit homelessness, stop fleeing, and remain in the city. Individual outcomes are dramatically better.
But here’s what surprised me. With 20 vouchers a month flowing into the market, average market rents in voucher-accepting neighborhoods are about 0.5% higher per placement than they would have been. The vouchers function as a demand-side wage subsidy to landlords. The recipients don’t lose because their rent is paid; their neighbors who didn’t get a voucher do lose, because the market price drifts up.
This isn’t novel — HUD studies have found this effect repeatedly in real life. But seeing it in the model made me update on how I weight the policy. Vouchers are an incomplete substitute for supply. They redistribute the burden of the housing shortage rather than ending it.
Rent control is more dramatic. When I run the universal RC scenario — all units rent-stabilized, citywide — 6 million households flee over 50 years. That’s 86% of the city’s housing demand walking out the door. Construction goes to zero. The 350,000 households left are mostly the original RC tenants who refuse to ever vacate.
If you skim the resulting stat sheet, the “equity score” looks fine: the people who remain are disproportionately low-income, because they’re the ones who got the RC handcuffs. But the city is gone. The equity metric is a survivor ratio.
The behavioral mechanism behind RC’s lock-in is its own widget:
Once you sign an RC lease, your unit is worth ~1.5× its market rent to you, by Thaler’s endowment effect. The breakeven to voluntarily move is “market rent below 1.5× my locked rent” — which almost never happens once your unit is below market. You stay even when your family grows, even when your job moves, even when the unit gets too small. The simulator models this explicitly, and you can see in the trace that RC stock gets frozen into massive misallocation — singles in 3-bedrooms, families in studios.
This is the real cost of universal rent control. It’s not that landlords lose money (they do, but they adjust). It’s that the unit allocation breaks. You preserve the right people in the wrong apartments.
Means-tested RC mitigates this somewhat — limit the protection to people below median income — but doesn’t solve it, because the binding constraint is still the endowment lock-in, not the income screen.
The interaction effects nobody talks about
The simulator surfaced three second-order effects I hadn’t seen articulated cleanly anywhere.
1. The demolition pathway. If you upzone a neighborhood with old housing stock, old buildings will get demolished. Always. The model has this as a deliberate mechanic: developers can buy + demolish buildings older than 50 years (non-historic) when the FAR upside is high enough. This is how new neighborhoods replace old ones — and it’s the only way an upzone actually increases density on already-built blocks rather than just on parking lots.
Cities that fight demolition (historic district expansions, “neighborhood character” preservation, landmarking aggressive enough to freeze whole districts) lock their stock at whatever density existed when the rules were written — usually the 1970s. The good news: tenant displacement from demolition is manageable if there’s a robust replacement-units guarantee. The bad news: forbid demolition entirely and you give up most of the supply gains from upzoning, regardless of how aggressive the FAR allowance is.
2. The wage-rent spiral. High rents → employers must offer higher wages to attract workers → wage-rent spiral. In the simulation, when citywide average rent exceeds a $2,500 baseline, every $500 above adds about +0.2%/yr to wage growth (capped at +1%/yr). This is a positive feedback loop. It explains why NYC and SF can have both very high rents and very high wages and stay stuck in that equilibrium.
The spiral has implications for who gets hurt. High-income workers see wage gains that partially offset rent inflation; low-income workers see less wage growth (their employers have more substitutes) and full rent inflation. The income gradient of housing pain steepens over time.
3. Equity-via-collapse. A scenario where 100 low-income households are housed out of 100 remaining looks 100% equitable. But 3,900 fled. Survivor ratios are not equity metrics.
I had to patch the grading function to handle this. If less than 20% of the original low-income agent count are still housed, the equity score is capped at C. If less than 5% remain, it’s an F regardless of survivor ratio. The previous version of the grading system was telling me Universal RC scored well on equity — which is technically true but morally indefensible. Survivor-ratio metrics are the housing-policy equivalent of measuring patient outcomes by surveying only the survivors.
The scoreboard
Here’s what the 48 scenarios shake out to:
A few patterns:
The top of the table is dominated by combinations. Every individual reform — parking elimination, ADU legalization, TOD bonus, even FAR 20 upzoning alone — gets a D or F. They only matter when stacked. This is unintuitive politically (it’s much easier to advocate for one named bill than for “a stack of fifteen”) but it’s the structural finding the model keeps reproducing.
Universal rent control is the worst single policy in the dataset, by a wide margin. Mandatory 100% affordable on every project is almost as bad — construction collapses entirely, rents on remaining stock more than double over the 50-year run.
The baseline (no policy at all) lands at D. Doing nothing is not neutral. It’s an active choice to let supply lag demand for half a century.
The B scenarios — everything-yimby, delayed-yimby — show the ceiling of what supply-side action alone can buy you. The C scenarios — combos of YIMBY + RC or YIMBY + vouchers — show what happens when you try to add tenant protections to supply: you trade some construction for some equity, and the grade doesn’t move.
Why no scenario gets an A
The most important finding is the one that’s not a single policy. It’s a structural fact: a 50-year window is not enough to undo 50 years of accumulated under-building.
NYC built ~30k units a year in the 1960s. By the 2010s it was ~15k, against a growing population. The deficit compounds. Even if you flip every YIMBY switch in 2020 and hold them on through 2070, the simulator suggests you can knock real rent down by 60%-ish, get 2-3M units built, and house most newcomers — but you’ll still have ~1M households without stable housing in 2070, mostly the cohort that got priced out in the 2010s-2020s and either fled or never re-entered.
What this implies, if the model is even directionally right:
-
Time is the scarce input, not money or political will. Every year the upzoning doesn’t pass, the deficit grows by another ~10k units and the labor capacity to absorb a future surge stays untrained.
-
Sequencing matters more than the menu. Delayed-yimby (full COYHO starting at month 120 instead of month 0) lands $1k/mo higher in 2070 than everything-yimby. A decade late means a generation more crowded.
-
The framing “we just need to build more” understates the difficulty by a factor of ~10×. “Build more” means: pass the zoning, and tax the land windfall, and clear the construction labor pipeline, and maintain it across multiple recessions and rate cycles, and hold political legitimacy when neighborhoods see cranes everywhere for 30 years. Any one of those failing kills most of the gain.
-
Demand-side tools are not substitutes for supply, but they are real complements. Vouchers reduce homelessness in the short run while supply catches up. Means-tested RC stops the worst displacement. Eviction protection (the kind that doesn’t break the formal market) provides a backstop. None of them work alone — but they extend the survival horizon while construction does its slow thing.
-
There’s no Magic Single Lever. The discourse keeps looking for one. There isn’t one. The model keeps refusing to find one.
What this was actually like to build
I want to flag the meta-story briefly, because it shaped what the model is.
I built this over about 20 sessions with Claude (the AI), using it as a collaborator. The Rust engine — Stone-Geary utility, DMP search, the auction system, the developer pro forma with capital-stack DSCR checks — is maybe 5,000 lines I wrote with Claude pairing. The frontend (React + WASM) is another 3,000. I’d write the prompt, sketch the mechanism, push back on the implementation, and iterate. Some sessions Claude implemented features I’d designed. Some sessions Claude flagged second-order effects I’d missed (the wage-rent spiral and the equity-via-collapse glitch were both Claude finds during scan reviews of the engine).
The Gemini calibration loop was the more interesting collaboration. I had Gemini critique the engine six separate times — pose as a housing economist, look for ways the model’s biased, find policies it can’t fairly represent. Each round produced 10-15 concrete improvements. The current compute_grade_full function with the equity-via-collapse guard, the rent-burden penalty, the debt-spiral check — all of those came out of pushing on the model with structured critique.
What I’m not claiming is that this model is right. What I’m claiming is that building it taught me more about housing than reading another 50 NYT op-eds would have. A model is an external memory for your causal beliefs. Once you commit them to code, you have to face which ones are inconsistent with each other.
Try it. Disagree with it. Tell me what’s wrong.
The simulator is at kaighn.com/yimby. It’s playable; you can dial up to the FAR 20 upzone you’ve always wanted, or zero out construction with 100% affordable mandate, or run pure rent control and watch the city evaporate.
The mechanisms I’ve described above are all explicit and documented — every step of the tick loop, every parameter, every coefficient is in SIMULATION.md. If you think a coefficient is wrong, send me the citation; if you think a mechanism is missing, send me the spec. I’ll add it. The model is a living object — version 19 of the engine doesn’t agree with version 1 on most quantitative claims, because version 1 was wrong about a lot.
The thing I’m most confident in, the thing the simulator hammered into me over a hundred runs, is the simplest possible claim and probably the least satisfying one: the housing crisis is not a single problem with a single solution. It’s a tangle of supply constraints, behavioral lock-ins, demand subsidies, and political windows. The honest answer to “what should we do” is most of them, in the right order, sustained for 30+ years.
Which is to say, we should start.