Overview

Every peso in the budget is a claim on an economy of a certain size, financed by revenues of a certain reach, against a debt of a certain weight. Before any department or sector is read on its own terms, it helps to fix that backdrop: how fast output is growing, what prices are doing, how much government collects and spends, and how heavy debt service has become. Those four things decide how much room the budget has, and they are moving in ways that tighten it.

This report sets that scene. It reads the recent macroeconomic record against the government’s own forecasts and targets, then traces the fiscal position from revenue and spending through the deficit, the debt stock, and the rising cost of carrying it. Two questions run through it. Are the projections the budget rests on realistic, judged against the forecasts the DBCC has actually published edition after edition? And are the medium-term targets being hit? The answers, read off the charts, are mostly no.

Actuals come from the national accounts (PSA), the Bureau of the Treasury’s cash operations, and BIR tax statistics, compiled in the PH-Econ-Data repository. The forecast vintages and fiscal targets are drawn from successive editions of the DBM Budget of Expenditures and Sources of Financing (BESF) and the DBCC Medium-Term Fiscal Framework.

1 Executive summary

The government’s growth forecasts have been consistently optimistic. Edition after edition, the BESF has projected growth near 6–6.5%. Output grew 2.3% in the latest quarter and has spent most of the last two decades below the forecast fan except during the post-pandemic rebound. The revenue and deficit math in the budget assumes an economy that runs faster than the one the data show.

Inflation keeps overshooting the target it is forecast to sit in. The BESF pencils in 2–4% almost every year. Actual inflation broke above it in 2018, again in the 2022–23 surge that peaked near 9%, and again in 2026 on food and energy shocks.

The labor market is the one series the government has forecast roughly right. Unemployment spiked to 17.6% in the April 2020 lockdown, fell to a record-low 3.8% by 2024, and has edged back to 6.0%. The DBCC’s forecasts have bracketed 4–5% and mostly held, in contrast to its growth and inflation calls.

Revenue has not moved; spending has. Revenue has held near 16% of GDP for two decades, 15.9% in the latest four quarters against 16.1% in 2019. Spending stepped up through the pandemic and stayed there, 21.4% now against 19.5% before COVID. The deficit is closing from the spending side, not the revenue side.

Every medium-term framework has promised the same consolidation, and the deficit keeps arriving above target. Successive MTFPs and the current MTFF all chart the deficit falling to 2–3% of GDP within a few years. The realized deficit is -5.5% now, down from its 2021 peak near 9% but still above the 3.5% the current framework sets for 2026.

Debt roughly doubled and the framework’s glide back down has not started. National government debt rose from about 42% of GDP before the pandemic to 66.0% now, above the 60% reference. Every framework since 2004 projected debt falling; actual debt jumped and has stayed high.

Debt service is eating the budget from both sides. Interest now takes 20.4% of revenue and 15.1% of spending, both rising as pandemic-era borrowing rolls over at higher rates. That is money committed before any program is funded.

2 Growth: forecast against outcome

The clearest test of whether the budget’s growth assumption is realistic is to put every edition’s forecast next to what actually happened.

gplot <- gdp_q %>% filter(Quarter >= x1)
ggplot() +
  covid_layer +
  geom_vline(xintercept = admin_lines, linetype = 3, color = "grey60") +
  annotate("text", x = admin_lines + 60, y = 0.122, label = admin_labs,
           hjust = 0, fontface = "bold", size = 3, alpha = 0.85) +
  geom_hline(yintercept = 0, color = "grey60") +
  geom_path(data = v_gdp, aes(Date, mid, group = grp, color = "BESF forecast"),
            linewidth = 0.5, alpha = 0.5) +
  geom_point(data = v_gdp, aes(Date, mid, color = "BESF forecast"),
             size = 0.7, alpha = 0.5) +
  geom_line(data = gplot, aes(Quarter, GrowthRate, color = "Actual"), linewidth = 1.1) +
  geom_point(data = gnow, aes(Quarter, GrowthRate, color = "Actual"), size = 2.2) +
  annotate("text", x = gnow$Quarter - 90, y = gnow$GrowthRate - 0.014,
           label = paste0(pc(gnow$GrowthRate), "%"), color = "black",
           fontface = "bold", size = 3.3, hjust = 1) +
  scale_color_manual(values = c("Actual" = "black", "BESF forecast" = "#0072b2"),
                     breaks = c("Actual", "BESF forecast")) +
  scale_x_date(breaks = seq.Date(x1, x2, by = "4 years"), date_labels = "%Y") +
  scale_y_continuous(labels = percent) +
  coord_cartesian(xlim = c(x1, x2), ylim = c(-0.18, 0.135)) +
  labs(x = NULL, y = "Real GDP growth (% YoY)",
       title = "The government has forecast 6–7% growth for years; the economy keeps undershooting",
       subtitle = "Quarterly real GDP growth (black) against each BESF edition's projection fan (blue). The MTFF target band is 6.5–8.0%.",
       caption = str_c("Actual growth from PSA (constant 2018 prices). Each blue path is one BESF edition's ",
                       "adjusted-year and 0–2 year projections. Shaded column marks the 2020 COVID contraction.")) +
  theme_fiscal() +
  guides(color = guide_legend(override.aes = list(alpha = 1, linewidth = 1, size = 1.5)))

Each blue path is one BESF edition, drawn from the year it adjusts through its two-year projection horizon. Two things stand out. The fan sits high and flat, clustered around 6–6.5% in almost every edition, which is the growth the budget’s revenue targets are sized against. And the black actual line spends most of its length below that fan. Growth matched the forecasts in the mid-2010s, collapsed in 2020, overshot briefly on the rebound, and has since slid back to 2.3%, under the fan again. The recent softness owes something to the El Niño drought and the 2026 oil shock, but the pattern is older than either: the DBCC’s central case has leaned optimistic for most of two decades.

3 Inflation: forecast against outcome

iplot <- infl %>% filter(Month >= x1)
inow  <- iplot %>% slice_max(Month, n = 1)
ggplot() +
  covid_layer +
  geom_ribbon(data = v_infl, aes(Date, ymin = lo, ymax = hi, group = grp),
              fill = "grey55", alpha = 0.18) +
  geom_path(data = v_infl, aes(Date, mid, group = grp, color = "BESF target"),
            linewidth = 0.4, alpha = 0.5) +
  geom_line(data = iplot, aes(Month, Inflation, color = "Actual"), linewidth = 1.1) +
  geom_point(data = inow, aes(Month, Inflation, color = "Actual"), size = 2) +
  annotate("text", x = inow$Month + 110, y = inow$Inflation, label = paste0(pc(inow$Inflation), "%"),
           color = "#d55e00", fontface = "bold", size = 3.3, hjust = 0) +
  geom_hline(yintercept = 0, color = "grey70") +
  scale_color_manual(values = c("Actual" = "#d55e00", "BESF target" = "grey45"),
                     breaks = c("Actual", "BESF target")) +
  scale_x_date(breaks = seq.Date(x1, x2, by = "4 years"), date_labels = "%Y") +
  scale_y_continuous(labels = percent) +
  coord_cartesian(xlim = c(x1, x2)) +
  labs(x = NULL, y = "Headline inflation (% YoY)",
       title = "Inflation keeps breaking out of the band it is forecast to stay in",
       subtitle = "Monthly headline inflation (orange) against each BESF edition's 2–4% target range (grey ribbons)",
       caption = str_c("Actual CPI from PSA (all items, national). Grey ribbons span each BESF edition's ",
                       "lower-to-upper inflation target across its projection horizons.")) +
  theme_fiscal() +
  guides(color = guide_legend(override.aes = list(alpha = 1, linewidth = 1)))

The grey ribbons are the DBCC’s inflation targets, edition by edition, almost always the 2–4% band. The orange line is what happened. It fits the band for long stretches, then breaks out: the 2018 TRAIN-and-rice episode, the 2022–23 surge that peaked near 9% and was the worst price shock since 2008, and the 2026 rise on drought and oil. For the budget these breakouts cut two ways. They lift nominal GDP and nominal revenue mechanically, and they erode the real value of every peso appropriated, so a flat nominal allocation is a real cut when prices run this fast. Several of the agency reviews on this site turn on that distinction.

4 Unemployment: a fast recovery, now edging up

Unemployment is not part of the fiscal program, so no target in the budget rides on it. But the DBCC forecasts it in every BESF, and it is the plainest read on whether the economy the budget operates in is generating work.

x0 <- as.Date("2005-01-01")
uplot <- unemp %>% filter(Period >= x0)
unow   <- uplot %>% slice_max(Period, n = 1)
ggplot() +
  covid_layer +
  geom_vline(xintercept = admin_lines, linetype = 3, color = "grey60") +
  annotate("text", x = admin_lines + 60, y = 0.176, label = admin_labs,
           hjust = 0, fontface = "bold", size = 3, alpha = 0.85) +
  geom_ribbon(data = v_unemp, aes(Date, ymin = lo, ymax = hi, group = grp),
              fill = "grey55", alpha = 0.18) +
  geom_path(data = v_unemp, aes(Date, mid, group = grp, color = "BESF forecast"),
            linewidth = 0.4, alpha = 0.5) +
  geom_line(data = uplot, aes(Period, Unemployment, color = "Actual"), linewidth = 1.1) +
  geom_point(data = unow, aes(Period, Unemployment, color = "Actual"), size = 2) +
  annotate("text", x = unow$Period - 120, y = unow$Unemployment + 0.013,
           label = paste0(pc(unow$Unemployment), "%"), color = "black",
           fontface = "bold", size = 3.3, hjust = 1) +
  geom_hline(yintercept = 0, color = "grey70") +
  scale_color_manual(values = c("Actual" = "black", "BESF forecast" = "grey45"),
                     breaks = c("Actual", "BESF forecast")) +
  scale_x_date(breaks = seq.Date(x0, x2, by = "4 years"), date_labels = "%Y") +
  scale_y_continuous(labels = percent) +
  coord_cartesian(xlim = c(x0, x2), ylim = c(0, 0.19)) +
  labs(x = NULL, y = "Unemployment rate",
       title = "Unemployment fell to record lows after COVID, and is now drifting up",
       subtitle = "Monthly unemployment rate (black) against each BESF edition's forecast range (grey ribbons)",
       caption = str_c("Actual from the PSA Labour Force Survey; series uses the 2005 revised definition and is shown from 2005. ",
                       "Grey ribbons span each BESF edition's lower-to-upper unemployment forecast.")) +
  theme_fiscal() +
  guides(color = guide_legend(override.aes = list(alpha = 1, linewidth = 1)))

The line runs the other way from the last two charts. Unemployment sat near 5% before the pandemic, spiked to 17.6% in the April 2020 lockdown as activity stopped, then fell steadily to a record-low 3.8% in 2024 as the recovery pulled people back to work. It has since edged up to 6.0% through 2025 and into 2026, alongside the growth slowdown. The grey ribbons are the DBCC’s forecasts, and here the record is different: the forecasts have bracketed 4–5%, and the actual rate has mostly landed inside or below them. Of the three macro variables the budget rests on, the labour market is the one the government has read roughly right.

Two caveats sit under the headline number. The low unemployment rate coexists with underemployment above 10%, workers who have jobs but want more hours, so the labour market is tighter on paper than in take-home terms. And the 2005 redefinition, which added an availability-to-work criterion, cut the measured rate by several points, which is why the series here starts in 2005 rather than 2001.

5 The fiscal position: a deficit closing from one side

Revenue, spending, and the gap between them, as shares of GDP.

fa <- fiscal %>% select(Quarter, Revenue, Expenditure, Deficit, PrimaryBalance) %>%
  filter(Quarter >= x1)
tgt_long <- mtff %>% select(Date, Revenue, Expenditure, Deficit) %>%
  pivot_longer(-Date, names_to = "Particular", values_to = "Value")
fa_lab <- fa %>% filter(Quarter == max(Quarter)) %>%
  pivot_longer(-Quarter, names_to = "Particular", values_to = "v") %>%
  mutate(Particular = recode(Particular, PrimaryBalance = "Primary balance"))
ggplot() +
  covid_layer +
  geom_vline(xintercept = admin_lines, linetype = 3, color = "grey60") +
  annotate("text", x = admin_lines + 60, y = 0.235, label = admin_labs,
           hjust = 0, fontface = "bold", size = 3, alpha = 0.85) +
  geom_hline(yintercept = 0, color = "grey60") +
  geom_line(data = fa, aes(Quarter, Revenue, color = "Revenue"), linewidth = 1.2) +
  geom_line(data = fa, aes(Quarter, Expenditure, color = "Expenditure"), linewidth = 1.2) +
  geom_line(data = fa, aes(Quarter, Deficit, color = "Deficit"), linewidth = 1.2) +
  geom_line(data = fa, aes(Quarter, PrimaryBalance, color = "Primary balance"), linewidth = 0.8) +
  geom_line(data = tgt_long, aes(Date, Value, color = Particular),
            linewidth = 0.8, linetype = "3313") +
  geom_point(data = fa_lab, aes(Quarter, v, color = Particular), size = 2) +
  geom_text(data = fa_lab, aes(Quarter, v, color = Particular, label = paste0(pc(v), "%")),
            hjust = 0, nudge_x = 60, fontface = "bold", size = 3, show.legend = FALSE) +
  scale_color_manual(values = ind_col,
                     breaks = c("Revenue", "Expenditure", "Deficit", "Primary balance")) +
  scale_x_date(breaks = seq.Date(x1, x2, by = "4 years"), date_labels = "%Y") +
  scale_y_continuous(labels = percent) +
  coord_cartesian(xlim = c(x1, x2), ylim = c(-0.10, 0.24)) +
  labs(x = NULL, y = "% of GDP",
       title = "Revenue is flat, spending ratcheted up, and the deficit is the difference",
       subtitle = "Rolling 4-quarter revenue, expenditure, deficit, and primary balance. Dashed lines are current MTFF targets.",
       caption = str_c("Fiscal indicators from BTr cash operations, as rolling 4-quarter shares of GDP. ",
                       "Dashed lines are the MTFF 2022–28 targets.\nPrimary balance = deficit excluding interest payments.")) +
  theme_fiscal() +
  guides(color = guide_legend(nrow = 1, override.aes = list(linewidth = 1.2)))

Revenue is the top pair’s lower line and it barely moves: near 16% of GDP throughout, 15.9% now. Expenditure is above it, and it did move, stepping up through 2020–21 and staying near 21–22%, 21.4% now against 19.5% in 2019. The deficit line at the bottom is the difference between them. It blew out to almost 9% of GDP in 2021 and has narrowed to -5.5% since. The narrowing is coming from spending drifting down off its pandemic peak, not from revenue climbing, because revenue is flat. The dashed targets show the plan: revenue is meant to rise and the deficit to keep falling toward 3%. The revenue dash pulls away from the actual revenue line, which is the gap the whole consolidation depends on closing.

The thin amber line is the primary balance, the deficit before interest. It sits much closer to zero than the headline deficit, which means a large share of the deficit is interest on past borrowing rather than current primary spending.

6 The medium-term program, framework by framework

The budget is written against the Medium-Term Fiscal Framework, the DBCC’s rolling statement of where revenue, spending, the deficit, and debt are meant to go. The current MTFF runs to 2028.

mtff %>%
  transmute(Year,
            `Revenue (% GDP)`     = Revenue,
            `Expenditure (% GDP)` = Expenditure,
            `Deficit (% GDP)`     = Deficit,
            `Debt (% GDP)`        = Debt) %>%
  mutate(across(-Year, ~ paste0(sprintf("%.1f", .x * 100), "%"))) %>%
  kbl_clean(font = 13, align = "rrrrr")
Year Revenue (% GDP) Expenditure (% GDP) Deficit (% GDP) Debt (% GDP)
2022 15.2% 22.9% -7.6% 61.8%
2023 15.3% 21.4% -6.1% 61.2%
2024 15.6% 20.7% -5.1% 60.0%
2025 16.0% 20.2% -4.1% 58.3%
2026 16.5% 20.0% -3.5% 56.6%
2027 17.0% 20.2% -3.2% 53.4%
2028 17.6% 20.6% -3.0% 51.1%

DBM Medium-Term Fiscal Framework (MTFF 2022–28). Deficit shown as a negative balance; expenditure is the disbursement program (here, revenue minus the deficit).

The current framework is a consolidation: deficit down from 7.6% of GDP in 2022 to 3.0% by 2028, debt easing from about 62% toward 51%, with revenue doing the work by climbing almost three points of GDP to 17.6%. What the single framework hides is that this is the latest in a line of nearly identical promises. Putting the successive frameworks on one axis shows the pattern.

act_def <- fiscal %>% transmute(Quarter, Deficit) %>% filter(Quarter >= as.Date("2004-01-01"))
ad_now <- act_def %>% filter(Quarter == max(Quarter))
ggplot() +
  covid_layer +
  geom_hline(yintercept = 0, color = "grey70") +
  geom_path(data = besf_def, aes(Date, mid, group = grp, color = "BESF vintage"),
            linewidth = 0.5, alpha = 0.5) +
  geom_path(data = fw_def, aes(Date, mid, group = grp, color = grp), linewidth = 0.8) +
  geom_point(data = fw_def, aes(Date, mid, color = grp), shape = 15, size = 1.4) +
  geom_line(data = act_def, aes(Quarter, Deficit, color = "Actual"), linewidth = 1.2) +
  geom_point(data = ad_now, aes(Quarter, Deficit), color = "black", size = 2) +
  annotate("text", x = ad_now$Quarter + 100, y = ad_now$Deficit, label = paste0(pc(ad_now$Deficit), "%"),
           color = "black", fontface = "bold", size = 3.2, hjust = 0) +
  scale_color_manual(values = fw_col, breaks = fw_breaks) +
  scale_x_date(breaks = seq.Date(as.Date("2004-01-01"), x2, by = "4 years"), date_labels = "%Y") +
  scale_y_continuous(labels = percent) +
  coord_cartesian(xlim = c(as.Date("2004-01-01"), x2), ylim = c(-0.10, 0.01)) +
  labs(x = NULL, y = "Deficit (% of GDP)",
       title = "Every framework has promised the deficit would fall to 2–3%; then it didn't",
       subtitle = "Realized deficit (black) against each administration's MTFP/MTFF target path and the BESF budget-cycle vintages",
       caption = str_c("Framework target paths and BESF vintages compiled from successive BESF editions; ",
                       "actual from BTr. MTFP/MTFF = Medium-Term Fiscal Program/Framework set by the DBCC.")) +
  theme_fiscal() +
  guides(color = guide_legend(nrow = 2, override.aes = list(linewidth = 1, shape = NA)))

Read left to right, each colored path is one administration’s medium-term deficit target, and the faded grey lines are the year-by-year BESF budget-cycle projections. They all point the same way: down, to a deficit of 2–3% of GDP within a few years. The black actual line is what happened. Aquino III’s framework (blue) roughly held, the one period where targets and outcomes met. Duterte’s original program (vermillion) was tracking until 2020, when COVID blew a hole in it and forced the revised path (orange). The current MTFF (green) starts from that post-pandemic high and charts the same descent everyone before it charted. Whether it lands where the others mostly didn’t depends on the revenue that has not yet materialized.

7 Debt: targets reset, outcomes stuck

dplot <- debt %>% filter(Quarter >= as.Date("2004-01-01"))
dp_now <- dplot %>% filter(Quarter == max(Quarter))
ggplot() +
  covid_layer +
  geom_hline(yintercept = 0.60, linetype = "dotted", color = "grey50") +
  annotate("text", x = as.Date("2004-06-01"), y = 0.615,
           label = "60% sustainability reference", hjust = 0, size = 3, color = "grey40") +
  geom_path(data = debt_vint, aes(Date, mid, group = grp, color = "BESF vintage"),
            linewidth = 0.5, alpha = 0.5) +
  geom_path(data = fw_debt, aes(Date, mid, group = grp, color = grp), linewidth = 0.8) +
  geom_point(data = fw_debt, aes(Date, mid, color = grp), shape = 15, size = 1.4) +
  geom_line(data = dplot, aes(Quarter, Debt, color = "Actual"), linewidth = 1.2) +
  geom_point(data = dp_now, aes(Quarter, Debt), color = "black", size = 2) +
  annotate("text", x = dp_now$Quarter + 100, y = dp_now$Debt + 0.02, label = paste0(pc(dp_now$Debt), "%"),
           color = "black", fontface = "bold", size = 3.2, hjust = 0) +
  scale_color_manual(values = fw_col, breaks = fw_breaks) +
  scale_x_date(breaks = seq.Date(as.Date("2004-01-01"), x2, by = "4 years"), date_labels = "%Y") +
  scale_y_continuous(labels = percent) +
  coord_cartesian(xlim = c(as.Date("2004-01-01"), x2), ylim = c(0.35, 0.80)) +
  labs(x = NULL, y = "NG debt (% of GDP)",
       title = "Debt targets keep being reset downward; actual debt jumped and stayed",
       subtitle = "Realized debt-to-GDP (black) against MTFP/MTFF framework targets and BESF budget-cycle vintages",
       caption = str_c("Actual NG debt from BTr over rolling 4-quarter GDP. Framework and vintage paths from ",
                       "successive BESF editions. 60% is a common emerging-market sustainability reference, not a formal rule.")) +
  theme_fiscal() +
  guides(color = guide_legend(nrow = 2, override.aes = list(linewidth = 1, shape = NA)))

The same story in the debt stock. Before the pandemic, debt was falling through the 40s and every framework projected it staying low. COVID took it to the low 60s in two years, and it has drifted up since, to 66.0% now, above the 60% reference. The current MTFF (green) projects it back down toward 51% by 2028. That descent is the mirror image of the deficit consolidation in the previous section, and it runs on the same assumption: revenue rising and the deficit closing on schedule. With the actual line flat-to-rising and growth below forecast, the glide has not begun.

8 The cost of that debt

A high debt stock is carriable if servicing it is cheap. It is getting less cheap, because pandemic-era borrowing is rolling over into higher rates.

ib <- fiscal %>%
  transmute(Quarter, `% of revenues` = IntRev, `% of expenditures` = IntExp) %>%
  filter(Quarter >= x1) %>%
  pivot_longer(-Quarter, names_to = "metric", values_to = "v") %>% filter(!is.na(v))
inow_r <- fiscal %>% filter(Quarter == max(Quarter))
ib_now <- ib %>% group_by(metric) %>% filter(Quarter == max(Quarter)) %>% ungroup()
ggplot(ib, aes(Quarter, v, color = metric)) +
  covid_layer +
  geom_vline(xintercept = admin_lines, linetype = 3, color = "grey60") +
  annotate("text", x = admin_lines + 60, y = 0.41, label = admin_labs,
           hjust = 0, fontface = "bold", size = 3, alpha = 0.85) +
  geom_line(linewidth = 1.2) +
  geom_point(data = ib_now, aes(Quarter, v, color = metric), size = 2) +
  geom_text(data = ib_now, aes(Quarter, v, color = metric, label = paste0(pc(v), "%")),
            hjust = 0, nudge_x = 45, fontface = "bold", size = 3, show.legend = FALSE) +
  scale_color_manual(values = interest_col) +
  scale_x_date(breaks = seq.Date(x1, x2, by = "4 years"), date_labels = "%Y") +
  scale_y_continuous(labels = percent) +
  coord_cartesian(xlim = c(x1, as.Date("2026-12-31")), ylim = c(0, 0.42)) +
  labs(x = NULL, y = "Interest payments as a share",
       title = "Interest is taking a rising share of both revenue and spending",
       subtitle = "National government interest payments as a share of revenues and of total expenditures",
       caption = "Rolling 4-quarter values from BTr cash operations.") +
  theme_fiscal()

Interest payments fell for most of the 2000s and 2010s, from around 30% of revenue under Macapagal-Arroyo to roughly 10% by the mid-2010s, as debt came down and rates fell. That has reversed. Interest now absorbs 20.4% of revenue and 15.1% of total spending, and both are climbing. This is the most direct line from the fiscal position to the budget: interest is a first charge on revenue, ahead of any program, so a rising interest share shrinks the discretionary space that departments and sectors compete over before the competition starts.

9 Where the revenue comes from

If revenue is the constraint the whole program leans on, it is worth seeing what it is made of.

taxcats <- c("I. Taxes on Net Income and Profit", "II. Excise Taxes",
             "III. Value-Added Tax", "IV. Percentage Taxes", "V. Other Taxes")
taxes <- tax_types %>%
  filter(TaxType %in% taxcats, !is.na(Effort)) %>%
  mutate(TaxType = str_remove(TaxType, "^.+\\.\\s"),
         TaxType = factor(TaxType, levels = c("Taxes on Net Income and Profit",
           "Value-Added Tax", "Excise Taxes", "Percentage Taxes", "Other Taxes")))
tax_pal <- c("Taxes on Net Income and Profit" = "#cc79a7", "Value-Added Tax" = "#117733",
             "Excise Taxes" = "#999933", "Percentage Taxes" = "#88ccee", "Other Taxes" = "#aa4499")
ggplot(taxes, aes(Year, Effort, fill = TaxType)) +
  covid_layer +
  geom_area(alpha = 0.85) +
  geom_vline(xintercept = admin_lines, linetype = 3, color = "grey70") +
  annotate("text", x = admin_lines + 90, y = 0.135, label = admin_labs,
           hjust = 0, fontface = "bold", size = 2.9, alpha = 0.85) +
  scale_x_date(breaks = seq.Date(x1, as.Date("2025-01-01"), by = "4 years"), date_labels = "%Y") +
  scale_y_continuous(labels = percent, expand = expansion(mult = c(0, 0.04))) +
  scale_fill_manual(values = tax_pal) +
  coord_cartesian(xlim = c(x1, as.Date("2025-06-30"))) +
  labs(x = NULL, y = "% of GDP",
       title = "BIR tax effort is flat, and income tax carries it",
       subtitle = "Bureau of Internal Revenue collections as a share of GDP, by tax type",
       caption = str_c("BIR tax statistics over PSA GDP. BIR is the larger collection agency; ",
                       "customs (BOC) adds roughly another 3–4% of GDP not shown here.")) +
  theme_fiscal() + guides(fill = guide_legend(reverse = TRUE, nrow = 2))

The height of the stack is BIR tax effort, and it is close to flat: around 10–12% of GDP for two decades, with total national government tax effort near 14–15% once customs is added. The mix moved more than the level. Income tax is the largest block and does most of the moving; VAT became a steadier second pillar after it went to 12% in 2006; excise stepped up after the 2013 sin-tax reform. What the picture does not show is any structural break upward in the total. The reforms of the last decade rebalanced the mix and roughly held the ratio; they did not lift it to the 17% the framework now needs.

That is the fiscal situation in one line. The consolidation the budget promises is a revenue story, and the forecasts it rests on have leaned optimistic for two decades. Until the revenue arrives, the deficit closes slowly from the spending side, debt stays high, interest keeps rising, and the space every department and sector competes for keeps tightening. The rest of the reports on this site read individual budgets against that backdrop.

10 A note on the data

Sources. Actuals: national accounts (real GDP) from the Philippine Statistics Authority; cash operations and debt from the Bureau of the Treasury; tax collections from the Bureau of Internal Revenue; prices from the PSA CPI; the labour force from the PSA Labour Force Survey (2005 revised definition). These are compiled in the public PH-Econ-Data repository and pulled from it at knit time. Forecasts and targets: the DBM Budget of Expenditures and Sources of Financing (BESF) macro assumptions and fiscal program, and the DBCC Medium-Term Fiscal Framework, compiled from successive editions and embedded in this file.

Reading the vintages. Each BESF edition publishes an adjusted estimate for its current year and projections zero to two years out. Plotting one path per edition gives the forecast fan, which shows the DBCC’s central case as it stood at each budget cycle, against the outcome that followed. Framework paths are the multi-year MTFP/MTFF deficit and debt targets; the BESF budget-cycle vintages join each edition’s near-term readings.

Method. Fiscal indicators are rolling four-quarter values over rolling four-quarter nominal GDP, which removes within-year seasonality. Real GDP growth is year-on-year at constant 2018 prices; inflation is year-on-year headline CPI. The 60% debt reference is a convention from the debt-sustainability literature, not a formal Philippine rule. Forecast and target values are the government’s own projections, not outcomes, and are shown so the actual path can be read against what the budget assumed.