Place-Based Policy

Helping places or helping people?

Most social programs help people wherever they live. Place-based policies help a place instead. Examples include tax breaks for firms in poor areas, wage subsidies for local workers, and big public projects like dams and highways. The goal is to lift struggling areas.

The hard question is who actually gains. Money aimed at a place does not stay with the people who were there.

Who captures the gains?

Suppose a zone pays a subsidy to everyone who works there. Wages after the subsidy go up, so the zone becomes more attractive. Two forces then kick in:

  1. People move in. If workers can move easily, new workers arrive to claim the subsidy.
  2. Rents rise. More people compete for the same housing. If housing supply is tight, rents go up a lot.

Higher rents eat into the subsidy. Who ends up with the gains depends on two numbers:

  • Worker mobility. The more easily workers move in, the more the subsidy is spread across newcomers and pushed into rents.
  • Housing supply elasticity. The easier it is to build, the less rents rise, and the more the subsidy stays with workers.

When workers are mobile and housing is tight, landlords capture most of the gain. This is the core lesson of the Spatial Equilibrium model applied to policy.

What the evidence says

  • Empowerment Zones gave firms wage credits for hiring zone residents. Jobs and wages for residents rose (Busso, Gregory and Kline 2013).
  • The Tennessee Valley Authority raised manufacturing in the region for decades, but much of that growth moved from other places (Kline and Moretti 2014).
  • Opportunity Zones barely moved house prices in the zones (Chen, Glaeser and Wessel 2023).

The Model View. A zone pays a subsidy to workers. You set the subsidy, how easily workers move in, and how easily housing gets built. The model finds the new population and rent. The bars show how much of the subsidy ends up with incumbent workers and how much with landlords.

#| standalone: true
#| viewerHeight: 620

library(shiny)

ui <- fluidPage(
  tags$head(tags$style(HTML("
    .info-box {
      background: #eaf2f8; border-radius: 6px; padding: 14px;
      margin-top: 12px; font-size: 13px; line-height: 1.8;
    }
    .info-box b { color: #2c3e50; }
  "))),

  sidebarLayout(
    sidebarPanel(
      width = 3,
      sliderInput("sub", "Wage subsidy (% of wage):",
                  min = 0, max = 20, value = 10, step = 1),
      sliderInput("mob", "How easily workers move in (0 = nobody, 10 = very easily):",
                  min = 0, max = 10, value = 4, step = 0.5),
      sliderInput("hse", "Housing supply elasticity:",
                  min = 0.1, max = 5, value = 0.5, step = 0.1),
      uiOutput("info")
    ),
    mainPanel(
      width = 9,
      fluidRow(
        column(6, plotOutput("bars", height = "460px")),
        column(6, plotOutput("curve", height = "460px"))
      )
    )
  )
)

server <- function(input, output, session) {

  w0 <- 50      # wage, $ thousands per year
  r0 <- 15      # rent, $ thousands per year
  u0 <- w0 - r0 # what workers get elsewhere

  solve_zone <- function(s, eta, kappa) {
    rent <- function(N) r0 * N^(1 / kappa)           # N is population relative to start
    # migration: population grows with the zone's advantage over elsewhere
    gap <- function(N) N - exp(eta * ((w0 * (1 + s) - rent(N)) - u0) / u0)
    N <- if (eta == 0) 1 else uniroot(gap, c(0.5, 50))$root
    r <- rent(N)
    list(N = N, r = r,
         worker_gain = w0 * s - (r - r0),     # per incumbent worker
         landlord_gain = r - r0,              # per incumbent unit
         cost = w0 * s * N)                   # subsidy paid per original worker
  }

  model <- reactive(solve_zone(input$sub / 100, input$mob, input$hse))

  output$bars <- renderPlot({
    m <- model()
    s <- input$sub / 100
    vals <- c(w0 * s, m$worker_gain, m$landlord_gain)
    par(mar = c(6, 4.5, 3, 1))
    b <- barplot(vals, col = c("#7f8c8d", "#27ae60", "#e74c3c"),
                 names.arg = c("Subsidy per\nworker", "Incumbent\nworker gain", "Landlord gain\nper unit"),
                 ylab = "$ thousands per year", main = "Who gets the subsidy?",
                 ylim = c(min(0, vals) - 1, max(10, 1.2 * max(vals))))
    abline(h = 0)
    text(b, vals + 0.4, sprintf("%.1f", vals), cex = 0.9)
  })

  output$curve <- renderPlot({
    par(mar = c(4.5, 4.5, 3, 1))
    ks <- seq(0.1, 5, length.out = 60)
    s <- input$sub / 100
    share <- sapply(ks, function(k) {
      m <- solve_zone(s, input$mob, k)
      if (s == 0) NA else 100 * m$worker_gain / (w0 * s)
    })
    plot(ks, share, type = "l", lwd = 3, col = "#27ae60", ylim = c(0, 100),
         xlab = "Housing supply elasticity", ylab = "% of subsidy kept by incumbent workers",
         main = "Easier building, more for workers")
    abline(v = input$hse, lty = 3, col = "#2c3e50", lwd = 2)
  })

  output$info <- renderUI({
    m <- model()
    s <- input$sub / 100
    kept <- if (s == 0) "n/a" else paste0(round(100 * m$worker_gain / (w0 * s)), "%")
    tags$div(class = "info-box",
      HTML(paste0(
        "<b>Population change:</b> ", sprintf("%+.0f", 100 * (m$N - 1)), "%<br>",
        "<b>Rent:</b> $", sprintf("%.1f", m$r), "k (was $", r0, "k)<br>",
        "<b>Share kept by incumbent workers:</b> ", kept, "<br>",
        "<b>Subsidy cost per original worker:</b> $", sprintf("%.1f", m$cost), "k"
      ))
    )
  })
}

shinyApp(ui, server)

Things to try

  • Set mobility to 0. No one moves in, rents do not change, and incumbent workers keep the whole subsidy. This is close to a subsidy tied to current residents, as in Empowerment Zones.
  • Raise mobility to 10 with tight housing (elasticity 0.2). Newcomers pour in, rents jump, and landlords capture most of the subsidy.
  • Keep mobility high but raise housing elasticity to 5. New housing absorbs the newcomers, rents rise less, and workers keep more.
  • Watch the cost. When people move in, the subsidy is paid to more workers, so the total cost grows even though each incumbent gains less.

The case for and against

For: Some people cannot easily move, because of family, home ownership, or cost. Helping their place may be the only way to reach them.

Against: Gains often go to landowners, and activity may just move from one place to another.

The simulation shows one design lesson. Policies tied to people who already live there keep more of the gains with those people than policies that reward anyone who shows up.

Connections

Did you know?

  • The Tennessee Valley Authority was created by Congress in 1933 as part of the New Deal. It built dams across the region to supply power and control floods.
  • The federal Empowerment Zones program designated its first zones in 1994, including parts of Atlanta, Baltimore, Chicago, Detroit, New York, and Philadelphia-Camden.
  • Opportunity Zones were created by the 2017 Tax Cuts and Jobs Act. Governors nominated low-income census tracts, and more than 8,000 tracts were designated.

Key papers