Gentrification & Displacement

The debate

Gentrification — the process by which higher-income residents move into lower-income neighborhoods, raising rents and changing neighborhood character — is one of the most contested topics in urban economics. The central question: does gentrification displace existing residents?

The mechanism

The process typically unfolds as follows:

  1. A low-rent neighborhood becomes attractive to higher-income households (proximity to jobs, cultural amenities, architecture, or simply affordability relative to other neighborhoods)
  2. Newcomers move in, increasing demand for housing
  3. Rents and property values rise
  4. For renters, higher rents mean higher housing costs. Some can’t afford to stay and leave (displacement). For owners, rising values are a wealth gain.
  5. Commercial activity shifts to serve the new, higher-income population. The neighborhood changes.

What does the evidence say?

The evidence on displacement is surprisingly mixed:

  • Vigdor (2002) and McKinnish, Walsh, and White (2010) find modest displacement effects. Most incumbent residents in gentrifying neighborhoods don’t move at higher rates than comparable residents in non-gentrifying areas.
  • Ellen and O’Regan (2011) find that incumbents who stay benefit from improved amenities — better schools, lower crime, cleaner streets.
  • Ding, Hwang, and Divringi (2016) find that displacement effects are concentrated among vulnerable populations: renters, the elderly, racial minorities, and those with lower credit scores.

The puzzle: gentrification clearly changes neighborhoods, but the displacement channel is hard to detect empirically. This may be because (a) displacement is modest, (b) it’s concentrated in subpopulations, or (c) it’s hard to distinguish from normal mobility.

The Identification Challenge. Measuring displacement requires knowing the counterfactual: would residents have moved anyway? High-mobility populations (renters, young adults) move frequently regardless of gentrification. The simulation below lets you see how rent increases, tenure type, and rent control policy interact to produce displacement over time. See also: Difference-in-Differences for how researchers compare gentrifying vs non-gentrifying neighborhoods.

#| standalone: true
#| viewerHeight: 720

library(shiny)

ui <- fluidPage(
  tags$head(tags$style(HTML("
    .stats-box {
      background: #f0f4f8; border-radius: 6px; padding: 14px;
      margin-top: 12px; font-size: 14px; line-height: 1.9;
    }
    .stats-box b { color: #2c3e50; }
    .good { color: #27ae60; font-weight: bold; }
    .bad  { color: #e74c3c; font-weight: bold; }
    .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("init_rent", "Initial rent ($/month):",
                  min = 500, max = 2000, value = 1000, step = 50),

      sliderInput("migration_rate", "Incoming high-income migration (per year):",
                  min = 0, max = 15, value = 5, step = 1),

      sliderInput("frac_renter", "Fraction renters (%):",
                  min = 20, max = 90, value = 60, step = 5),

      checkboxInput("rent_control", "Rent control policy", value = FALSE),

      actionButton("go", "Run 10-year simulation", class = "btn-primary", width = "100%"),

      uiOutput("info")
    ),

    mainPanel(
      width = 9,
      fluidRow(
        column(4, plotOutput("rent_plot", height = "420px")),
        column(4, plotOutput("comp_plot", height = "420px")),
        column(4, plotOutput("disp_plot", height = "420px"))
      )
    )
  )
)

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

  sim <- reactive({
    input$go
    r0 <- input$init_rent
    mig <- input$migration_rate / 100  # as fraction
    frac_rent <- input$frac_renter / 100
    rc <- input$rent_control

    years <- 0:10
    n_years <- length(years)

    # Initialize
    rent <- numeric(n_years)
    share_low <- numeric(n_years)
    share_high <- numeric(n_years)
    displaced_cum <- numeric(n_years)
    original_remaining <- numeric(n_years)

    rent[1] <- r0
    share_low[1] <- 1.0
    share_high[1] <- 0.0
    displaced_cum[1] <- 0
    original_remaining[1] <- 100  # percent

    # Rent growth depends on high-income influx
    for (t in 2:n_years) {
      # New high-income arrivals push rents up
      rent_pressure <- mig * (1 + share_high[t - 1])

      if (rc) {
        # Rent control: limit annual increase to 3%
        rent[t] <- rent[t - 1] * (1 + min(rent_pressure, 0.03))
      } else {
        rent[t] <- rent[t - 1] * (1 + rent_pressure)
      }

      # Displacement: renters leave when rent exceeds affordability
      rent_increase <- (rent[t] - r0) / r0  # cumulative rent increase

      # Displacement probability depends on rent increase and renter share
      # Renters face displacement; owners don't (they benefit from appreciation)
      disp_rate <- frac_rent * rent_increase * 0.15  # annual displacement among remaining
      disp_rate <- min(disp_rate, 0.25)  # cap annual displacement

      # Track original residents
      original_remaining[t] <- original_remaining[t - 1] * (1 - disp_rate)

      # Neighborhood composition
      displaced_cum[t] <- 100 - original_remaining[t]
      share_high[t] <- min(share_high[t - 1] + mig, 1 - original_remaining[t] / 100)
      share_high[t] <- max(share_high[t], 0)
      share_low[t] <- 1 - share_high[t]
    }

    list(years = years, rent = rent,
         share_low = share_low * 100, share_high = share_high * 100,
         displaced_cum = displaced_cum,
         original_remaining = original_remaining,
         rent_change_pct = (rent[n_years] - r0) / r0 * 100,
         final_disp = displaced_cum[n_years],
         avg_income_change = share_high[n_years] * 40)  # rough proxy
  })

  output$rent_plot <- renderPlot({
    s <- sim()
    par(mar = c(4.5, 5, 3, 1))

    plot(s$years, s$rent, type = "b", lwd = 3, pch = 19, col = "#e74c3c",
         xlab = "Year", ylab = "Monthly rent ($)",
         main = "Rent Trajectory",
         ylim = c(min(s$rent) * 0.9, max(s$rent) * 1.1))

    abline(h = s$rent[1], lty = 2, col = "gray60", lwd = 1.5)
    text(5, s$rent[1], "Initial rent", pos = 3, cex = 0.8, col = "gray50")

    # Annotate final rent change
    text(10, s$rent[11], paste0("+", round(s$rent_change_pct), "%"),
         pos = 3, col = "#e74c3c", font = 2, cex = 0.9)
  })

  output$comp_plot <- renderPlot({
    s <- sim()
    par(mar = c(4.5, 5, 3, 1))

    plot(s$years, s$share_low, type = "l", lwd = 3, col = "#3498db",
         xlab = "Year", ylab = "Share (%)",
         main = "Neighborhood Composition",
         ylim = c(0, 105))

    polygon(c(s$years, rev(s$years)),
            c(s$share_low, rep(0, length(s$years))),
            col = adjustcolor("#3498db", 0.2), border = NA)

    lines(s$years, s$share_high, lwd = 3, col = "#e67e22")
    polygon(c(s$years, rev(s$years)),
            c(rep(100, length(s$years)), rev(s$share_low)),
            col = adjustcolor("#e67e22", 0.2), border = NA)

    legend("right", bty = "n", cex = 0.85,
           legend = c("Low-income share", "High-income share"),
           col = c("#3498db", "#e67e22"), lwd = 3)
  })

  output$disp_plot <- renderPlot({
    s <- sim()
    par(mar = c(4.5, 5, 3, 1))

    plot(s$years, s$original_remaining, type = "b", lwd = 3, pch = 19,
         col = "#27ae60",
         xlab = "Year", ylab = "Original residents remaining (%)",
         main = "Displacement",
         ylim = c(0, 105))

    polygon(c(s$years, rev(s$years)),
            c(s$original_remaining, rep(0, length(s$years))),
            col = adjustcolor("#27ae60", 0.15), border = NA)

    # Displaced area
    polygon(c(s$years, rev(s$years)),
            c(rep(100, length(s$years)), rev(s$original_remaining)),
            col = adjustcolor("#e74c3c", 0.15), border = NA)

    text(8, (100 + s$original_remaining[9]) / 2,
         paste0(round(s$displaced_cum[11]), "% displaced"),
         col = "#e74c3c", font = 2, cex = 0.9)

    abline(h = 50, lty = 3, col = "gray70")
  })

  output$info <- renderUI({
    s <- sim()

    tags$div(class = "info-box",
      HTML(paste0(
        "<b>Rent increase (10yr):</b> <span class='",
        ifelse(s$rent_change_pct > 30, "bad", "good"), "'>+",
        round(s$rent_change_pct, 1), "%</span><br>",
        "<b>Displacement rate:</b> <span class='",
        ifelse(s$final_disp > 30, "bad", "good"), "'>",
        round(s$final_disp, 1), "%</span><br>",
        "<b>Original residents left:</b> ", round(s$original_remaining[11], 1), "%<br>",
        "<b>Avg income change:</b> +", round(s$avg_income_change, 0), "%"
      ))
    )
  })
}

shinyApp(ui, server)

Things to try

  • High migration rate + high renter fraction: rapid gentrification with substantial displacement. Rents spike and original residents leave quickly.
  • Low migration rate: slow gentrification. Even after 10 years, most original residents remain. This is the empirical pattern — gentrification is usually gradual.
  • Switch from 60% renters to 30% renters: displacement drops dramatically. Owners are insulated from rent increases (they benefit from appreciation). This matches the evidence that displacement is concentrated among renters.
  • Turn on rent control: rent growth is capped, reducing displacement. But the composition still changes because new units are filled by higher-income residents. Rent control slows displacement but doesn’t prevent neighborhood change.

The policy landscape

Gentrification policy typically targets one of two goals: preventing displacement or ensuring existing residents benefit from neighborhood improvements:

  • Rent stabilization limits annual rent increases, protecting long-term tenants. But it can reduce housing supply (landlords convert to condos or disinvest) and doesn’t protect new tenants.
  • Community land trusts remove land from the speculative market, ensuring permanently affordable housing. Successful examples include the Champlain Housing Trust (Burlington, VT).
  • Inclusionary zoning requires developers to include affordable units in new construction. This creates mixed-income neighborhoods but may reduce overall housing supply.
  • Right of first refusal gives existing tenants or community organizations the right to purchase buildings before they’re sold to outside investors.

No policy is a free lunch. The fundamental tension: neighborhood improvement benefits existing residents (lower crime, better amenities), but the associated rent increases can price them out.


Connections

  • Hedonic Pricing — gentrification shows up in hedonic regressions as rising implicit prices for neighborhood amenities (safety, walkability, restaurant access).
  • Zoning & Housing Supply — inelastic housing supply amplifies rent increases from gentrification. In elastic-supply cities, new construction absorbs demand and rents rise less.
  • Difference-in-Differences — researchers study gentrification’s effects by comparing gentrifying neighborhoods (treated) to similar neighborhoods that didn’t gentrify (control), relying on parallel trends.
  • Tiebout Sorting — gentrification is Tiebout sorting at the neighborhood level within a city, rather than across jurisdictions.

Did you know?

  • The term “gentrification” was coined by sociologist Ruth Glass in 1964, describing the process in London: “One by one, many of the working class quarters of London have been invaded by the middle classes… Once this process of ‘gentrification’ starts in a district it goes on rapidly until all or most of the original working class occupiers are displaced.”
  • Measuring displacement empirically is notoriously difficult. The problem is that high-mobility populations (renters, young adults) move frequently regardless of gentrification. To isolate the causal effect of gentrification on out-migration, you need to know the counterfactual — would these residents have moved anyway? Most studies find that the difference between mobility rates in gentrifying vs non-gentrifying neighborhoods is small, which is why the evidence on displacement is so mixed.
  • Community land trusts (CLTs) are one of the few mechanisms that can permanently decouple housing costs from land speculation. The CLT owns the land and leases it to homeowners, who own only the structure. When they sell, a resale formula limits the price appreciation, keeping the home affordable for the next buyer. The largest CLT in the US, the Champlain Housing Trust in Burlington, VT, manages over 700 units and has kept homes affordable through multiple housing booms.