India’s Public Foodgrain Procurement: Trends, Patterns & Policy Implications

Food Economy
Procurement
Agriculture Policy
A detailed analysis of foodgrain procurement by FCI and state agencies across marketing seasons, with regional breakdowns and MSP evolution.
Author

Pawan

Published

October 30, 2025

Modified

March 29, 2026

Overview

India operates one of the world’s largest public food procurement systems. The government procures wheat (rabi), paddy/rice (kharif), and coarse grains at the Minimum Support Price (MSP) through the Food Corporation of India (FCI) and state government agencies. Procured stocks underpin the Public Distribution System (PDS), midday-meal schemes, and the National Food Security Act (NFSA) welfare programmes.

Key policy features: - Procurement is price-floor insurance for farmers — FCI and state agencies buy all offered quantities at MSP. - Stocks feed welfare: NFSA covers 80 crore beneficiaries with 5 kg/person/month of subsidised grain. - Buffer norms guide minimum stock requirements for food security.


Setup

Code
library(data.table)
library(ggplot2)
library(ggiraph)
library(scales)
library(gt)
library(plotly)
library(viridis)
library(patchwork)

my_theme <- theme_minimal(base_size = 13) +
  theme(
    plot.title      = element_text(size = 16, face = "bold", hjust = 0.5, margin = margin(b = 8)),
    plot.subtitle   = element_text(size = 11, hjust = 0.5, color = "#7F8C8D"),
    plot.caption    = element_text(size = 9, color = "#95A5A6", hjust = 0),
    axis.title      = element_text(size = 12, face = "bold"),
    axis.text       = element_text(size = 10),
    axis.text.x     = element_text(angle = 45, vjust = 1, hjust = 1),
    legend.position = "bottom",
    legend.title    = element_blank(),
    panel.grid.major= element_line(color = "#ECF0F1", linewidth = 0.4),
    panel.grid.minor= element_blank(),
    strip.background= element_rect(fill = "#F8F9FA", color = NA),
    strip.text      = element_text(face = "bold", size = 11)
  )

Section 1 · Total Procurement by Crop

Code
t1 <- fread("/home/pawan/procurement/procurement.csv")
t1[Crop!="Rice"]->t1
## Summarise by crop and marketing season
proc_sum <- t1[, .(Total     = sum(Total, na.rm=TRUE),
                   FCI       = sum(FCI, na.rm=TRUE),
                   StateAgency = sum(StateAgency, na.rm=TRUE)),
               by = .(Crop, MarketingYear, MarketingSeason)]

proc_sum[, FCI_Share   := round(FCI/Total*100, 1)]
proc_sum[, State_Share := round(StateAgency/Total*100, 1)]
proc_sum[, tt := paste0("<b>",Crop,"</b> | Season: ",MarketingSeason,
                         "<br>Total: ",round(Total,1)," LMT",
                         "<br>FCI: ",round(FCI,1)," (",FCI_Share,"%)",
                         "<br>States: ",round(StateAgency,1)," (",State_Share,"%)")]

## By-crop faceted bar
p1 <- ggplot(proc_sum, aes(x=MarketingYear, y=Total, fill=Crop)) +
  geom_bar_interactive(aes(tooltip=tt, data_id=paste(Crop,MarketingYear)),
                        stat="identity", width=0.75, alpha=0.9) +
  facet_wrap(~Crop, scales="free_y") +
  scale_fill_brewer(palette="Set2") +
  scale_y_continuous(labels=comma_format()) +
  my_theme + theme(legend.position="none") +
  labs(title="Foodgrain Procurement by Crop & Marketing Season",
       subtitle="Hover over bars for FCI vs state agency breakdown",
       y="Quantity (Lakh Metric Tonnes)", x="Marketing Year",
       caption="Source: DFPD Procurement Portal | Analysis: Pawan")

girafe(ggobj=p1, width_svg=13, height_svg=7,
       options=list(
         opts_tooltip(css="background:#fff;color:#333;padding:10px;border-radius:6px;border:1px solid #ddd;font-size:12px;"),
         opts_hover(css="opacity:0.9;stroke:#333;stroke-width:1.5;"),
         opts_hover_inv(css="opacity:0.3;"),
         opts_zoom(min=0.8, max=3),
         opts_sizing(rescale=TRUE, width=1)))

Section 2 · FCI vs State Agency Split

The procurement machinery involves two tiers: FCI (central agency) and state government agencies. Their relative roles have shifted over time — states have taken on more responsibility as part of decentralisation.

Code
proc_long <- melt(proc_sum[, .(Crop,MarketingYear,FCI,StateAgency)],
                  id.vars=c("Crop","MarketingYear"),
                  variable.name="Agency", value.name="Qty")
proc_long[, tt := paste0(Agency,"\nCrop: ",Crop,"\nSeason: ",MarketingYear,
                          "\n",round(Qty,1)," LMT")]

p2 <- ggplot(proc_long, aes(x=MarketingYear, y=Qty, fill=Agency)) +
  geom_bar_interactive(aes(tooltip=tt, data_id=Agency),
                        stat="identity", position="stack", width=0.75, alpha=0.9) +
  facet_wrap(~Crop, scales="free_y") +
  scale_fill_manual(values=c("FCI"="#2C3E50","StateAgency"="#E67E22"),
                    labels=c("FCI"="FCI","StateAgency"="State Agencies")) +
  scale_y_continuous(labels=comma_format()) +
  my_theme +
  labs(title="FCI vs State Agency Procurement Split",
       subtitle="States increasingly driving procurement in newer seasons",
       y="Quantity (LMT)", x="Marketing Year",
       caption="Source: DFPD | Analysis: Pawan")

girafe(ggobj=p2, width_svg=13, height_svg=7,
       options=list(
         opts_tooltip(css="background:#fff;color:#333;padding:8px;border-radius:5px;border:1px solid #ddd;"),
         opts_hover(css="opacity:0.85;stroke-width:1.5;"),
         opts_sizing(rescale=TRUE, width=1)))

Section 3 · Procurement Trend Analysis

Code
## Total annual procurement across all crops
annual_total <- proc_sum[, .(Total_All = sum(Total)), by = MarketingYear]
setorder(annual_total, MarketingYear)
annual_total[, YoY := round((Total_All/shift(Total_All)-1)*100, 1)]

## Line chart with growth annotations
p3 <- ggplot(annual_total, aes(x=MarketingYear, y=Total_All, group=1,
                                text=paste0(MarketingYear,"\n",round(Total_All,1)," LMT",
                                            "\nYoY: ",YoY,"%"))) +
  geom_col(fill="#3498DB", alpha=0.4, width=0.7) +
  geom_line(color="#2C3E50", linewidth=1.3) +
  geom_point(color="#2C3E50", size=3.5) +
  geom_text(aes(label=ifelse(!is.na(YoY), paste0(YoY,"%"), "")),
            vjust=-1.2, size=3.2, color="#E74C3C") +
  my_theme +
  labs(title="Total Foodgrain Procurement — All Crops",
       subtitle="YoY growth rates annotated in red",
       y="Quantity (LMT)", x="Marketing Year",
       caption="Source: DFPD | Analysis: Pawan")

ggplotly(p3, tooltip="text") |> layout(hovermode="x unified")

Section 4 · Summary Statistics Table

Code
proc_stats <- proc_sum[, .(
  Avg_Procurement = round(mean(Total),1),
  Max_Procurement = round(max(Total),1),
  Min_Procurement = round(min(Total),1),
  Avg_FCI_Share   = round(mean(FCI_Share),1),
  Seasons         = .N
), by=Crop]

proc_stats |>
  gt() |>
  tab_header(title="Procurement Summary Statistics by Crop") |>
  cols_label(Crop="Crop", Avg_Procurement="Avg (LMT)",
             Max_Procurement="Max (LMT)", Min_Procurement="Min (LMT)",
             Avg_FCI_Share="Avg FCI Share %", Seasons="No. of Seasons") |>
  fmt_number(columns=2:4, decimals=1) |>
  data_color(Avg_Procurement,
             colors=scales::col_numeric(c("#D5F5E3","#1A5276"), domain=NULL)) |>
  opt_stylize(style=3) |>
  tab_source_note("Source: DFPD Central Food Grains Procurement Portal")
Procurement Summary Statistics by Crop
Crop Avg (LMT) Max (LMT) Min (LMT) Avg FCI Share % No. of Seasons
Paddy 566.3 913.7 246.6 2.3 19
Wheat 252.8 433.4 92.2 5.3 25
Source: DFPD Central Food Grains Procurement Portal

Section 5 · Policy Context

Code
## Paddy procurement regional breakdown (if available)
if ("State" %in% names(t1)) {
  paddy_state <- t1[Crop=="Paddy",
    .(Total=sum(Total,na.rm=TRUE)), .(State, MarketingYear)]
  top_states <- paddy_state[, .(Total=sum(Total)), by=State][order(-Total)][1:10, State]
  paddy_top  <- paddy_state[State %in% top_states]

  p_state <- ggplot(paddy_top, aes(x=MarketingYear, y=Total, fill=State)) +
    geom_bar(stat="identity", position="stack", width=0.75, alpha=0.9) +
    scale_fill_viridis_d() +
    my_theme +
    labs(title="Paddy Procurement by Top States",
         y="Quantity (LMT)", x="Marketing Year",
         caption="Source: DFPD | Analysis: Pawan")
  ggplotly(p_state) |> layout(hovermode="x unified")
}

Key insights:

  1. Marketing Season for procurement is different for rabi and kharif crops, For Rabi crops (Wheat) is begin from 1st April and end 31st March, For Kharif crops (Paddy) is begin from 1st October end at 30th September
  2. Paddy dominates procurement in volume terms, with Chhattisgarh, MP, Punjab and Haryana as the largest procuring states.
  3. Wheat procurement fluctuates more sharply due to production variability in the Indo-Gangetic plain.
  4. State agencies have grown as a share of total procurement, reflecting greater state-level operational capacity.
  5. COVID-19 impact (2020–21): procurement held firm, underpinning the free-grain scheme (PMGKAY) for 80 crore beneficiaries.