The Monocentric City
The Alonso-Muth-Mills model
All jobs are at the CBD (central business district). Workers choose where to live, trading off commuting costs against housing costs. In equilibrium, no one wants to move — which means land rent must decline with distance from the CBD to compensate for longer commutes. This declining curve is the rent gradient.
The rent gradient
In the simplest version, rent declines linearly with distance:
\[R(d) = R_{CBD} - t \cdot d\]
where \(d\) is distance from the CBD, \(t\) is the commuting cost per mile, and \(R_{CBD}\) is rent at the center. The city edge \(d^*\) is where rent falls to the agricultural rent \(R_a\):
\[d^* = \frac{R_{CBD} - R_a}{t}\]
Beyond \(d^*\), land is worth more in agriculture than in housing, so the city stops.
Comparative statics
- Higher transport cost \(t\): steeper gradient, smaller city. Workers pay more per mile of commute, so they bid less for distant land. The city shrinks inward.
- Higher income/wages: ambiguous. Higher income means more demand for space (flatter gradient, bigger city), but also higher time cost of commuting (steeper gradient, smaller city). Empirically, the space effect dominates — richer cities are more spread out.
- Higher population: more people compete for land near the CBD, pushing \(R_{CBD}\) up. The city expands outward until the marginal resident is indifferent between the edge and the center.
#| standalone: true
#| viewerHeight: 700
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("transport", "Transport cost ($/mile):",
min = 50, max = 500, value = 200, step = 25),
sliderInput("income", "Wage/income ($1000s):",
min = 20, max = 120, value = 60, step = 5),
sliderInput("ag_rent", "Agricultural rent ($/acre):",
min = 50, max = 500, value = 100, step = 25),
sliderInput("pop", "Population (thousands):",
min = 50, max = 1000, value = 300, step = 25),
actionButton("go", "Update city", class = "btn-primary", width = "100%"),
uiOutput("info")
),
mainPanel(
width = 9,
fluidRow(
column(4, plotOutput("rent_plot", height = "400px")),
column(4, plotOutput("density_plot", height = "400px")),
column(4, plotOutput("city_plot", height = "400px"))
)
)
)
)
server <- function(input, output, session) {
city <- reactive({
input$go
t_cost <- input$transport
income <- input$income * 1000
r_ag <- input$ag_rent
pop <- input$pop * 1000
# CBD rent determined by population pressure and income
# Higher pop and income push CBD rent up
r_cbd <- r_ag + sqrt(pop * income * t_cost) * 0.01
# City radius: where rent = agricultural rent
d_star <- (r_cbd - r_ag) / t_cost
# Ensure reasonable bounds
d_star <- max(d_star, 0.1)
# Distance vector
d <- seq(0, d_star * 1.3, length.out = 200)
# Rent gradient
rent <- pmax(r_cbd - t_cost * d, r_ag)
# Population density declines with distance (proportional to rent)
density_cbd <- pop / (pi * d_star^2) * 2
density <- density_cbd * pmax(1 - d / d_star, 0)
# Total area
area <- pi * d_star^2
# Average rent (within city)
avg_rent <- (r_cbd + r_ag) / 2
list(d = d, rent = rent, density = density,
d_star = d_star, r_cbd = r_cbd, r_ag = r_ag,
area = area, avg_rent = avg_rent, t_cost = t_cost,
density_cbd = density_cbd)
})
output$rent_plot <- renderPlot({
c <- city()
par(mar = c(4.5, 4.5, 3, 1))
plot(c$d, c$rent, type = "l", lwd = 3, col = "#2c3e50",
xlab = "Distance from CBD (miles)",
ylab = "Rent ($/acre)",
main = "Rent Gradient")
abline(h = c$r_ag, lty = 2, col = "#e74c3c", lwd = 2)
abline(v = c$d_star, lty = 3, col = "#7f8c8d", lwd = 1.5)
text(c$d_star, c$r_cbd * 0.9,
paste0("City edge\nd* = ", round(c$d_star, 1), " mi"),
pos = 4, cex = 0.8, col = "#7f8c8d")
legend("topright", bty = "n", cex = 0.85,
legend = c("Rent gradient", "Agricultural rent"),
col = c("#2c3e50", "#e74c3c"), lwd = c(3, 2), lty = c(1, 2))
})
output$density_plot <- renderPlot({
c <- city()
par(mar = c(4.5, 4.5, 3, 1))
d_city <- c$d[c$d <= c$d_star]
dens_city <- c$density[seq_along(d_city)]
plot(d_city, dens_city, type = "l", lwd = 3, col = "#3498db",
xlab = "Distance from CBD (miles)",
ylab = "Population density (per sq mi)",
main = "Population Density")
polygon(c(d_city, rev(d_city)),
c(dens_city, rep(0, length(d_city))),
col = adjustcolor("#3498db", 0.2), border = NA)
abline(v = c$d_star, lty = 3, col = "#7f8c8d", lwd = 1.5)
})
output$city_plot <- renderPlot({
c <- city()
par(mar = c(1, 1, 3, 1))
theta <- seq(0, 2 * pi, length.out = 100)
r_max <- c$d_star * 1.3
plot(NULL, xlim = c(-r_max, r_max), ylim = c(-r_max, r_max),
xlab = "", ylab = "", main = "City Footprint",
asp = 1, axes = FALSE)
# Fill city area
polygon(c$d_star * cos(theta), c$d_star * sin(theta),
col = adjustcolor("#e74c3c", 0.15), border = "#e74c3c", lwd = 2)
# CBD point
points(0, 0, pch = 19, cex = 2, col = "#2c3e50")
text(0, 0, "CBD", pos = 3, cex = 0.9, col = "#2c3e50", font = 2)
# Radius line
segments(0, 0, c$d_star, 0, lwd = 2, col = "#e74c3c", lty = 2)
text(c$d_star / 2, -c$d_star * 0.12,
paste0(round(c$d_star, 1), " mi"), cex = 0.85, col = "#e74c3c")
})
output$info <- renderUI({
c <- city()
tags$div(class = "info-box",
HTML(paste0(
"<b>City radius:</b> ", round(c$d_star, 1), " miles<br>",
"<b>CBD rent:</b> $", format(round(c$r_cbd), big.mark = ","), "/acre<br>",
"<b>Avg rent:</b> $", format(round(c$avg_rent), big.mark = ","), "/acre<br>",
"<b>City area:</b> ", format(round(c$area, 1), big.mark = ","), " sq mi"
))
)
})
}
shinyApp(ui, server)
Things to try
- Raise transport cost: the gradient steepens and the city shrinks. People can’t afford to live far out when commuting is expensive.
- Lower transport cost to $50: the city sprawls outward. This is what happened when cars replaced streetcars — lower \(t\) meant flatter gradients and suburban growth.
- Increase population: CBD rent rises as more people compete for central locations. The city expands to accommodate them.
- Raise income: the city grows because workers demand more space. This is consistent with the American pattern of higher-income suburbs.
Why cities change shape
The monocentric model explains the great reshaping of American cities in the 20th century. Before cars, commuting costs were high (walking, horse-drawn streetcars). Rent gradients were steep, and cities were compact and dense. Think of 1900 Manhattan or Chicago.
The automobile slashed \(t\). The gradient flattened. Suddenly, land 20 miles from the CBD was accessible and cheap. Suburbs exploded. Between 1950 and 2000, the share of Americans living in suburbs roughly doubled.
Rising incomes reinforced the pattern. Higher-income households demand more space (larger lots, bigger houses). Since space is cheaper at the edge, they moved outward — the classic “drive until you qualify” pattern. The poor were left in the center, not because the center was cheap (it wasn’t — small apartments, high per-square-foot costs) but because they couldn’t afford the commute.
Did you know?
- William Alonso published Location and Land Use in 1964, formalizing the idea that urban land rents reflect a tradeoff between commuting costs and access. He was building on Johann Heinrich von Thunen’s 1826 model of agricultural rings around a market town — the same logic, just applied to cities instead of farms.
- The monocentric model predicts that rent gradients should flatten as transport costs fall. Glaeser and Kahn (2004) confirmed this empirically: American cities became dramatically less dense as car ownership rose.
- LA vs NYC illustrate different gradients. NYC has a very steep gradient (extremely expensive center, rapid price drop with distance), reflecting its transit-oriented history. LA has a much flatter gradient, consistent with its car-oriented development. The monocentric model explains both as consequences of different transport cost structures.