The Costs of Inflation

Why inflation is costly

  • Shoeleather costs — effort to hold less cash when inflation is high.
  • Menu costs — the cost of changing posted prices.
  • Relative-price distortions — staggered price changes misallocate resources.
  • Redistribution (unexpected inflation) — fixed nominal contracts transfer wealth between borrowers and lenders.
  • Hyperinflation — all costs balloon; money stops working as a store of value.

Who wins from a surprise? (redistribution)

A one-year loan sets its nominal rate on expected inflation: \(i = r + \pi^e\). The lender’s realized (ex post) real return is \(i - \pi\).

  • If actual \(\pi >\) expected \(\pi^e\) → the borrower gains (repays in cheaper dollars).
  • If actual \(\pi <\) expected → the lender gains.

Try it. Fix the expected inflation the loan was priced on, then move actual inflation and watch who gains.

#| standalone: true
#| viewerHeight: 500

library(shiny)
ui <- fluidPage(
  tags$head(tags$style(HTML("body{font-family:'Inter',system-ui,sans-serif;}
    .sb{background:#f0f4f8;border-radius:6px;padding:12px 14px;margin-top:10px;font-size:14px;line-height:1.9;} .sb b{color:#1f3b73;}
    .win{color:#1c6b4a;font-weight:bold;} .lose{color:#b5462a;font-weight:bold;}"))),
  sidebarLayout(
    sidebarPanel(width=4,
      sliderInput("r","Real rate the loan targets  r (%):",min=0,max=5,value=2,step=1),
      sliderInput("pe","Expected inflation when signed  pi_e (%):",min=0,max=10,value=3,step=1),
      sliderInput("pa","ACTUAL inflation  pi (%):",min=0,max=15,value=3,step=1),
      uiOutput("sb")),
    mainPanel(width=8, plotOutput("plot",height="420px"))))
server <- function(input,output,session){
  output$plot <- renderPlot({
    exante <- input$r; expost <- (input$r+input$pe)-input$pa
    par(mar=c(3,4.6,2,1))
    barplot(c(`Ex ante\n(expected)`=exante,`Ex post\n(realized)`=expost),
            col=c("#9aa4b2","#1f3b73"),ylab="Lender's real return (%)",las=1,
            ylim=c(min(0,expost)-1,max(exante,expost)+1),main="Real return to the lender")
    abline(h=0,col="#5a6472")
  })
  output$sb <- renderUI({ i<-input$r+input$pe; expost<-i-input$pa; gap<-input$pa-input$pe
    who <- if(abs(gap)<1e-9) "No surprise — no redistribution." else if(gap>0)
      sprintf("Inflation surprised <b>high</b> → <span class='win'>borrower gains</span>, <span class='lose'>lender loses</span>.") else
      sprintf("Inflation surprised <b>low</b> → <span class='win'>lender gains</span>, <span class='lose'>borrower loses</span>.")
    HTML(sprintf("<div class='sb'>Nominal rate i = r + pi_e = <b>%d%%</b><br>Ex ante real = <b>%d%%</b><br>Ex post real = i - pi = <b>%d%%</b><br>%s</div>",i,input$r,expost,who)) })
}
shinyApp(ui,server)

What to notice

  • Set actual = expected → ex post equals ex ante → no redistribution. Surprises are what redistribute.
  • Push actual above expected → the lender’s realized return falls → borrower wins.
  • Menu, shoeleather, and relative-price costs happen even when inflation is fully expected; redistribution is the extra cost of the surprise.