← Back to blog
·12 min

Where do my taxes go? Building a French government budget dashboard with Nuxt.js and open data

Jonathan Delhoux

Jonathan Delhoux

Fullstack Developer, Technical Partner for Web Agencies

Share →

Where do my taxes go? Building a French government budget dashboard with Nuxt.js and open data

The project in one sentence

Turn the raw French government budget data, available as open data on data.economie.gouv.fr, into an interactive dashboard where any citizen can visualise where their taxes go. The result is accessible at ouvontmesimpots.fr.

This is not a theoretical exercise but a production site with real traffic, effective SEO and assumed technical trade-offs. The sections below describe what worked, the points of difficulty, and the decisions retained.

Why this project

The government budget concerns every citizen, yet it is rarely understood in detail. The data exists (France performs relatively well on open data) but it is scattered across barely readable CSV files, partially documented APIs and three-hundred-page PDFs rarely opened.

The objective was simple: a single, clear and visual entry point where a citizen can enter a tax amount and see concretely where each euro goes. Without budget jargon, without unusable Excel charts.

The tech stack and the reasons behind the choices

Nuxt 4 and TypeScript: the foundation

Nuxt imposed itself naturally. SSR is essential for SEO (a site about taxes must appear in Google) and the Nitro server routes are well suited to creating API endpoints that query and transform the Ministry of Finance data before passing it to the front end.

TypeScript is not optional on this type of project. When handling budget data with dozens of fields, amounts in millions and percentage calculations, static typing catches bugs that unit tests would have missed.

Chart.js: interactive charts

Chart.js was used via vue-chartjs for every chart: doughnuts for revenue, horizontal bars for expenditure by mission, line charts for monthly execution and debt trends. The library is lightweight, well documented and flexible enough for required customisations.

The main technical challenge concerns the expenditure bars with drill-down. When a user clicks on a mission (for example "Defence"), the bars expand to reveal the individual programmes. This requires managing open state, transition animations and container height recalculation. Non-trivial, but the result is smooth.

Tailwind CSS and dark mode

Tailwind v4 was used via @nuxt/ui. Dark mode is auto-detected (prefers-color-scheme) or toggled manually. Behind this apparent simplicity, every Chart.js chart must react to theme changes: axis colours, gridlines, tooltips, legends. A useChartTheme() composable was created to provide reactive colours to all charts.

Data architecture: the core of the project

The sources

The data comes from two main sources:

  • data.economie.gouv.fr, the Ministry of Finance API. It exposes the PLF (Finance Bill) with detailed revenues and expenditures, along with monthly budget execution statements
  • INSEE and Eurostat for GDP and the evolution of public debt as a percentage of GDP

The server pipeline

Each data type has its own server-side API route (/server/api/). The chosen approach concentrates transformation on the server side and delivers clean, display-ready data to the client.

Concrete example: the Ministry API returns expenditure line by line, with a mission code and a programme code. The server route aggregates by mission, sorts by descending amount, calculates percentages of the total, and groups programmes under each mission. The front end only has to iterate and render.

Another representative case: monthly execution. The Ministry provides cumulative data (running total since January). To obtain monthly amounts, which make sense in a chart, each month is subtracted from the previous one. The operation is performed on the server, not on the client.

Caching

All API routes are cached for one hour (s-maxage=3600). Budget data does not vary every five minutes, and this strategy avoids hammering the Ministry's APIs. A pragmatic choice: fresh enough for monthly updates, cached enough to absorb a traffic spike.

The features that matter

The "For every 100 euros in taxes" simulator

The flagship feature. The user enters an amount (100 euros, 1,000 euros, 10,000 euros) and immediately visualises the breakdown: this much for Defence, this much for Education, this much for debt servicing. Technically, it is a ratio of amount over total revenue applied to each mission. Visually, the device makes the budget tangible.

Dynamic insights

Rather than raw numbers, the dashboard calculates more meaningful metrics:

  • Debt per citizen (total debt divided by 68 million inhabitants)
  • Expenditure per second (approximately 1.3 million euros)
  • The "fiscal liberation date", the theoretical day when annual revenue covers expenditure

The full set is calculated dynamically in a useInsights() composable, based on actual data. No number is hardcoded.

Expenditure drill-down

Expenditure is presented by mission (the major budget categories). Clicking a bar opens the detail of individual programmes. The benefit is significant: "Defence Mission: 56 billion" remains abstract, but the envelope becomes readable once it breaks down into "Force Equipment" for 29 billion and "Force Preparation and Deployment" for 12 billion.

SEO and accessibility: considered from day one

A public-interest site invisible to Google does not meet its objective. SEO was planned from the start:

  • Full SSR, content sits in the initial HTML, not generated in JavaScript
  • Open Graph and Twitter Cards for social sharing
  • Schema.org (WebSite and FAQPage with four questions/answers)
  • Sitemap, robots.txt and llms.txt
  • Optimised meta descriptions and titles

On accessibility: ARIA labels on every interactive element, alt text for screen readers, contrast ratios respected in both light and dark modes.

GDPR: the strict minimum

Google Analytics is used for audience measurement, blocked by default. Consent Mode v2 is in place with a sober banner: accept, refuse, and that is all. No dark patterns, no banner covering half the screen, no "legitimate interest" hidden in a submenu.

The site works perfectly without any analytics cookies, which should be the reference model.

Key figures for the 2025 budget

Among the numbers highlighted by the dashboard:

  • Public debt represents approximately 113% of GDP in 2025, against 95% in 2015
  • The state spends around 1.3 million euros per second
  • The top three spending categories are School Education, Defence and Financial Commitments (debt servicing)

These numbers are not intended to produce an effect, only to inform. A well-informed citizen is in a better position to take part in the budget debate.

Lessons from the project

Working with public data is a formative experience. APIs are not always well documented, formats evolve between yearly editions, and cross-referencing multiple sources is sometimes needed to obtain a reliable figure. The outcome justifies the investment: this data belongs to the community, making it readable is both a technical and a civic act.

On the technical side, the pattern "server routes that transform, composables that expose, components that render" proved its robustness. It is clear, testable and maintainable.

View the result

The site is live: ouvontmesimpots.fr. Enter a tax amount to visualise the allocation euro by euro. Free, no signup, no advertising.

A dashboard or data visualisation project? Get in touch. Raw data turned into clear, interactive interfaces.

/ Share this

Share →

Available for sub-contractingToulouse · RemoteVue · Nuxt · Laravel · NodeAvailable for sub-contractingToulouse · RemoteVue · Nuxt · Laravel · Node
JDW.

Fullstack Developer, Technical Partner for Web Agencies, Toulouse

Network

© 2026 Jonathan Delhoux – JDW Development. All rights reserved.

Legal notice·Privacy policy·

[ Cookies ] This site uses cookies for its operation and, with your consent, to measure its audience. See our Privacy policy.