Fiscalité directe locale (REI) : foncier bâti, foncier non bâti, taxe d’habitation, CFE

Données - DGFIP

Code
source(here::here("_rinit.R"))
invisible(Sys.setlocale("LC_TIME", "fr_FR.UTF-8"))
# cd ~/iCloud/website/data/dgfip; /usr/local/bin/R -e 'quarto::quarto_render("rei.qmd")'
# cd ~/iCloud/website/data; sh _status/run_all_silent.sh --only dgfip

knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE,
                       fig.width = 9, fig.height = 5.5, dpi = 150)

rei_path <- here::here("data", "dgfip", "rei_national.parquet")
rei <- arrow::read_parquet(rei_path)

periode <- range(rei$Annee)

long <- rei |>
  dplyr::select(Annee, Population, dplyr::ends_with("_produit")) |>
  tidyr::pivot_longer(dplyr::ends_with("_produit"), names_to = "Taxe", values_to = "Produit") |>
  dplyr::mutate(Taxe = dplyr::recode(stringr::str_remove(Taxe, "_produit"),
    FNB = "Foncier non bâti", FB = "Foncier bâti",
    TH = "Taxe d'habitation", CFE = "CFE (ex-taxe professionnelle)")) |>
  dplyr::mutate(Taxe = factor(Taxe, levels = c("Foncier bâti", "Foncier non bâti",
                                                "Taxe d'habitation", "CFE (ex-taxe professionnelle)")))

taux_long <- rei |>
  dplyr::select(Annee, dplyr::ends_with("_taux_moyen_com")) |>
  tidyr::pivot_longer(dplyr::ends_with("_taux_moyen_com"), names_to = "Taxe", values_to = "Taux") |>
  dplyr::mutate(Taxe = dplyr::recode(stringr::str_remove(Taxe, "_taux_moyen_com"),
    FNB = "Foncier non bâti", FB = "Foncier bâti",
    TH = "Taxe d'habitation", CFE = "CFE"))

pal_taxes <- c("Foncier bâti" = "#c0392b", "Foncier non bâti" = "#27ae60",
               "Taxe d'habitation" = "#8e44ad", "CFE (ex-taxe professionnelle)" = "#3b6f8a",
               "CFE" = "#3b6f8a")

theme_rei <- theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold"),
        plot.subtitle = element_text(colour = "grey35"),
        panel.grid.minor = element_blank())

Le REI (fichier de recensement des éléments d’imposition à la fiscalité directe locale) est la source exhaustive de la DGFIP sur les quatre grandes taxes directes locales : taxe foncière sur les propriétés bâties (FB), taxe foncière sur les propriétés non bâties (FNB), taxe d’habitation (TH) et cotisation foncière des entreprises (CFE, héritière de la taxe professionnelle). Chaque millésime couvre ~35 000 communes et ~870 variables codées (bases, taux, produits, exonérations, dégrèvements…). Les chiffres ci-dessous sont des totaux nationaux (produit perçu par les communes et leurs groupements à fiscalité propre) reconstruits en sommant les ~35 000 lignes de chaque millésime, de 2009 à 2025.

Produit des quatre taxes locales

Code
rei |>
  dplyr::transmute(Annee, Communes,
                    `FB (Md€)`  = FB_produit  / 1e9,
                    `FNB (Md€)` = FNB_produit / 1e9,
                    `TH (Md€)`  = TH_produit  / 1e9,
                    `CFE (Md€)` = CFE_produit / 1e9) |>
  dplyr::filter(Annee %in% c(2009, 2015, 2020, 2021, periode[2])) |>
  gt::gt() |>
  gt::fmt_number(columns = -c(Annee, Communes), decimals = 1) |>
  gt::fmt_number(columns = Communes, decimals = 0, sep_mark = " ") |>
  gt::tab_header(title = "Produit des taxes directes locales, quelques millésimes-repères") |>
  gt::tab_options(table.width = "100%")
Produit des taxes directes locales, quelques millésimes-repères
Annee Communes FB (Md€) FNB (Md€) TH (Md€) CFE (Md€)
2009 36 681 13.5 0.8 11.0 34.8
2015 36 674 17.5 1.0 21.6 9.9
2020 34 969 20.6 1.0 23.6 11.0
2021 34 969 34.0 1.0 6.5 9.6
2025 34 907 42.8 1.1 0.0 11.5
Code
long |>
  ggplot(aes(Annee, Produit / 1e9, fill = Taxe)) +
  geom_col(position = "stack") +
  scale_y_continuous(labels = scales::label_number(big.mark = " ")) +
  scale_x_continuous(breaks = scales::breaks_pretty(9)) +
  scale_fill_manual(values = pal_taxes, name = NULL) +
  labs(title = "Produit des quatre taxes directes locales",
       subtitle = "Communes + groupements à fiscalité propre, milliards d'euros",
       x = NULL, y = "Md€") +
  theme_rei +
  theme(legend.position = "bottom")
Figure 1

Trois ruptures structurelles se lisent nettement :

  • 2010 : remplacement de la taxe professionnelle par la CFE (réforme de la fiscalité économique locale), qui redéfinit son assiette et fait mécaniquement chuter son produit apparent l’année de la bascule ;
  • 2018-2023 : suppression progressive de la taxe d’habitation sur les résidences principales, qui disparaît complètement des recettes communales à partir de 2023 (elle subsiste marginalement sur les résidences secondaires et logements vacants, non comptabilisée ici) ;
  • 2021 : en compensation, la part départementale de la taxe foncière sur le bâti est transférée aux communes, ce qui fait quasiment doubler le produit du foncier bâti perçu au niveau communal+intercommunal entre 2020 et 2021.

Évolution récente (2015-2025)

Code
long |>
  dplyr::filter(Annee >= 2015) |>
  ggplot(aes(Annee, Produit / 1e9, colour = Taxe)) +
  geom_line(linewidth = 1) +
  geom_point(size = 1.8) +
  scale_y_continuous(labels = scales::label_number(big.mark = " ")) +
  scale_x_continuous(breaks = scales::breaks_pretty(8)) +
  scale_colour_manual(values = pal_taxes, name = NULL) +
  labs(title = "Zoom sur la période récente",
       subtitle = "Produit par taxe, milliards d'euros", x = NULL, y = "Md€") +
  theme_rei +
  theme(legend.position = "bottom")
Figure 2

Le foncier bâti est ainsi devenu, de très loin, la première ressource fiscale directe des communes et de leurs groupements : il représente à lui seul plus des deux tiers du produit total des quatre taxes en 2025, contre un peu moins de la moitié en 2009.

Code
long |>
  dplyr::group_by(Annee) |>
  dplyr::mutate(Part = Produit / sum(Produit)) |>
  dplyr::ungroup() |>
  ggplot(aes(Annee, Part, fill = Taxe)) +
  geom_area(position = "stack") +
  scale_y_continuous(labels = scales::label_percent()) +
  scale_x_continuous(breaks = scales::breaks_pretty(9)) +
  scale_fill_manual(values = pal_taxes, name = NULL) +
  labs(title = "Structure du produit fiscal local",
       subtitle = "Part de chaque taxe dans le total des quatre", x = NULL, y = NULL) +
  theme_rei +
  theme(legend.position = "bottom")
Figure 3

Taux moyens communaux

Code
taux_long |>
  dplyr::filter(!is.nan(Taux)) |>
  ggplot(aes(Annee, Taux, colour = Taxe)) +
  geom_line(linewidth = 0.9) +
  geom_point(size = 1.6) +
  scale_y_continuous(labels = scales::label_number(suffix = " %")) +
  scale_x_continuous(breaks = scales::breaks_pretty(9)) +
  scale_colour_manual(values = pal_taxes, name = NULL) +
  labs(title = "Taux moyens communaux, votés par les conseils municipaux",
       subtitle = "Produit net / base nette, niveau communal uniquement", x = NULL, y = NULL) +
  theme_rei +
  theme(legend.position = "bottom")
Figure 4

Le taux moyen communal de foncier bâti bondit lui aussi en 2021 : les communes ont repris le taux départemental sur une base pourtant quasi inchangée, d’où un doublement apparent du taux affiché à assiette égale (neutre pour le contribuable, dont le taux global cumulé communes + département était déjà voté avant transfert).

Produit total par habitant

Code
rei |>
  dplyr::transmute(Annee,
                    `Par habitant (€)` = (FB_produit + FNB_produit + TH_produit + CFE_produit) / Population) |>
  ggplot(aes(Annee, `Par habitant (€)`)) +
  geom_col(fill = "#3b6f8a") +
  scale_y_continuous(labels = scales::label_number(big.mark = " ")) +
  scale_x_continuous(breaks = scales::breaks_pretty(9)) +
  labs(title = "Produit total des quatre taxes locales par habitant",
       subtitle = "France entière, euros courants", x = NULL, y = "€ / hab.") +
  theme_rei
Figure 5

Table complète

Code
rei |>
  dplyr::transmute(
    Année = Annee, Communes,
    `FNB (M€)` = round(FNB_produit / 1e6, 0),
    `FB (M€)`  = round(FB_produit  / 1e6, 0),
    `TH (M€)`  = round(TH_produit  / 1e6, 0),
    `CFE (M€)` = round(CFE_produit / 1e6, 0),
    `Taux FNB (%)` = round(FNB_taux_moyen_com, 2),
    `Taux FB (%)`  = round(FB_taux_moyen_com, 2),
    `Taux TH (%)`  = round(TH_taux_moyen_com, 2),
    `Taux CFE (%)` = round(CFE_taux_moyen_com, 2)
  ) |>
  dplyr::arrange(dplyr::desc(Année)) |>
  reactable::reactable(
    searchable = TRUE, pagination = TRUE, defaultPageSize = 20,
    compact = TRUE, resizable = TRUE, highlight = TRUE, wrap = TRUE,
    defaultColDef = reactable::colDef(
      align = "left", headerStyle = list(fontWeight = "bold"),
      style = list(whiteSpace = "normal", wordBreak = "break-word"))
  )

Source, méthode & données

Code
tibble::tibble(
  ` ` = c("Jeu de données", "Producteur", "Licence", "Fichier", "Mise à jour", "Méthode", "Observations"),
  `  ` = c(
    "REI — fichier de recensement des éléments d'imposition à la fiscalité directe locale, un fichier par année — [impots.gouv.fr](https://www.impots.gouv.fr/) / [data.gouv.fr](https://www.data.gouv.fr/)",
    "Direction générale des Finances publiques (DGFIP)",
    "Licence Ouverte / Open Licence 2.0 (Etalab)",
    sprintf("`data/dgfip/rei_national.parquet` (%s ko)", round(file.size(rei_path) / 1024)),
    format(as.Date(file.mtime(rei_path)), "%d %B %Y"),
    "Sommes nationales recalculées à partir des ~35 000 lignes communales de chaque millésime brut (formats hétérogènes selon les années : codes courts ou libellés complets, xlsx/csv). Niveaux retenus : commune + groupement à fiscalité propre (CFE : total tous niveaux, code `S01`).",
    sprintf("%d millésimes (%d-%d) ; %d variables suivies par taxe (base, taux, produit)",
            nrow(rei), periode[1], periode[2], 4)
  )
) |>
  gt::gt() |> gt::fmt_markdown(columns = `  `) |>
  gt::tab_options(table.width = "100%", column_labels.hidden = TRUE)
Jeu de données REI — fichier de recensement des éléments d’imposition à la fiscalité directe locale, un fichier par année — impots.gouv.fr / data.gouv.fr
Producteur Direction générale des Finances publiques (DGFIP)
Licence Licence Ouverte / Open Licence 2.0 (Etalab)
Fichier data/dgfip/rei_national.parquet (5 ko)
Mise à jour 22 septembre 2026
Méthode Sommes nationales recalculées à partir des ~35 000 lignes communales de chaque millésime brut (formats hétérogènes selon les années : codes courts ou libellés complets, xlsx/csv). Niveaux retenus : commune + groupement à fiscalité propre (CFE : total tous niveaux, code S01).
Observations 17 millésimes (2009-2025) ; 4 variables suivies par taxe (base, taux, produit)