VAT rates for 44 European countries — all EU-27 member states plus Norway, Switzerland, the United Kingdom, and more. EU rates sourced from the European Commission TEDB and checked daily. Published automatically when rates change.
- Standard, reduced, super-reduced, and parking rates
eu_memberflag on every country —truefor EU-27,falsefor non-EUvat_name— official name of the VAT tax in the country's primary official languagevat_abbr— short abbreviation used locally (e.g. "ALV", "MwSt", "TVA")format— human-readable VAT number format (e.g."ATU + 8 digits") — unique to this packagepattern— regex for VAT number validation + built-invalidateFormat()— free, no API key needed — unique to this package- TypeScript types included — works in Node.js and the browser
- JSON file committed to git — full rate-change history via
git log - Checked daily via GitHub Actions, new npm version published only when rates change
Available in 5 ecosystems:
| Language | Package | Install |
|---|---|---|
| JavaScript / TypeScript | npm | npm install eu-vat-rates-data |
| Python | PyPI | pip install eu-vat-rates-data |
| PHP | Packagist | composer require vatnode/eu-vat-rates-data |
| Go | pkg.go.dev | go get github.com/vatnode/eu-vat-rates-data-go |
| Ruby | RubyGems | gem install eu_vat_rates_data |
| Package | Auto-updates | VAT number format | Source |
|---|---|---|---|
| eu-vat-rates-data | ✅ daily (GitHub Actions) | ✅ format + pattern + validateFormat() |
EC TEDB (official) |
| sales-tax | ❌ manual | ❌ | hardcoded |
| eu-vat-rates | ❌ last 2023 | ❌ | hardcoded |
| eu-vat | ❌ last 2018 | ❌ | external API |
| vat-calculator | ❌ last 2015 | ❌ | hardcoded |
Two key differences: (1) every other package relies on manual updates or is abandoned — eu-vat-rates-data publishes automatically when rates change, same day. (2) This is the only package that includes VAT number format descriptions and regex patterns for all 44 countries, with a built-in validateFormat() function — no API key or network call needed.
npm install eu-vat-rates-data
# or
yarn add eu-vat-rates-data
# or
pnpm add eu-vat-rates-dataimport { getRate, getStandardRate, getAllRates, isEUMember, isKnownCountry, dataVersion } from 'eu-vat-rates-data'
// Full rate object for a country
const fi = getRate('FI')
// {
// country: 'Finland',
// currency: 'EUR',
// eu_member: true,
// vat_name: 'Arvonlisävero',
// vat_abbr: 'ALV',
// standard: 25.5,
// reduced: [10, 13.5],
// super_reduced: null,
// parking: null
// }
// Just the standard rate
getStandardRate('DE') // → 19
// EU membership check — false for non-EU countries (GB, NO, CH, ...)
if (isEUMember(userInput)) {
const rate = getRate(userInput) // type narrowed to EUMemberCode
}
// Dataset membership check — true for any of the 44 European countries
if (isKnownCountry(userInput)) {
const rate = getRate(userInput) // type narrowed to CountryCode
}
// All 44 countries at once
const all = getAllRates()
Object.entries(all).forEach(([code, rate]) => {
console.log(`${code}: ${rate.standard}%`)
})
// When were these rates last fetched?
console.log(dataVersion) // e.g. "2026-03-27"
// VAT number format validation — no API key, no network call
import { validateFormat } from 'eu-vat-rates-data'
validateFormat('ATU12345678') // → true
validateFormat('DE123456789') // → true
validateFormat('INVALID') // → false
// Access format metadata directly
const at = getRate('AT')
console.log(at.format) // "ATU + 8 digits"
console.log(at.pattern) // "^ATU\\d{8}$"
// Flag emoji from a 2-letter country code — no lookup table, computed from regional indicator symbols
import { getFlag } from 'eu-vat-rates-data'
getFlag('FI') // → '🇫🇮'
getFlag('DE') // → '🇩🇪'
getFlag('XX') // → '' (empty string for unknown/invalid codes)const { getRate, isEUMember, isKnownCountry } = require('eu-vat-rates-data')
console.log(getRate('FR').standard) // 20# Served directly from GitHub CDN:
https://cdn.jsdelivr.net/gh/vatnode/eu-vat-rates-data@main/data/eu-vat-rates-data.json
# Raw GitHub (always latest commit):
https://raw.githubusercontent.com/vatnode/eu-vat-rates-data/main/data/eu-vat-rates-data.json
const res = await fetch(
'https://cdn.jsdelivr.net/gh/vatnode/eu-vat-rates-data@main/data/eu-vat-rates-data.json'
)
const { rates } = await res.json()
console.log(rates.DE.standard) // 19interface VatRate {
country: string // "Finland"
currency: string // "EUR" (or "DKK", "GBP", …)
eu_member: boolean // true for EU-27, false for non-EU
vat_name: string // "Arvonlisävero" — official name in primary local language
vat_abbr: string // "ALV" — short abbreviation used locally
standard: number // 25.5
reduced: number[] // [10, 13.5] — sorted ascending
super_reduced: number | null // null when not applicable
parking: number | null // null when not applicable
format: string // "FI + 8 digits" — human-readable VAT number format
pattern: string // "^FI\\d{8}$" — regex for format validation, always present
}reduced may contain rates for special territories (e.g. French DOM departments, Azores/Madeira for Portugal, Canary Islands for Spain). All values come verbatim from EC TEDB.
Standard ISO 3166-1 alpha-2, with one EU convention: Greece is GR (TEDB internally uses EL, which this package normalises).
{
"version": "2026-03-31",
"source": "European Commission TEDB",
"rates": {
"FI": {
"country": "Finland",
"currency": "EUR",
"eu_member": true,
"vat_name": "Arvonlisävero",
"vat_abbr": "ALV",
"standard": 25.5,
"reduced": [10, 13.5],
"super_reduced": null,
"parking": null,
"format": "FI + 8 digits",
"pattern": "^FI\\d{8}$"
}
}
}Rates are fetched from the European Commission Taxes in Europe Database (TEDB) via its official SOAP web service:
- Refreshed: daily at 07:00 UTC
- Published: new npm version only when actual rates change (not on date-only updates)
- History:
git log -- data/eu-vat-rates-data.jsongives a full audit trail of VAT changes across the EU
Data is fetched by the eu-vat-rates-data repository and synced here daily.
Rates are bundled at install time. A new package version is published automatically whenever rates change — but your installed version will not update itself.
Recommended: add Renovate or Dependabot to your repo. They detect new versions and open a PR automatically whenever rates change — no manual update commands needed.
Need real-time accuracy? Fetch the always-current JSON directly:
https://cdn.jsdelivr.net/gh/vatnode/eu-vat-rates-data@main/data/eu-vat-rates-data.json
No package needed — parse it with a single fetch() / http.get() / file_get_contents() call and cache locally.
EU-27 member states:
AT BE BG CY CZ DE DK EE ES FI FR GR HR HU IE IT LT LU LV MT NL PL PT RO SE SI SK
Additional European countries:
AD AL BA CH GB GE IS LI MC MD ME MK NO RS TR UA XK
44 countries total.
This package provides VAT rates only. If you also need to validate EU VAT numbers against the official VIES database — confirming a business is VAT-registered — check out vatnode.dev, a simple REST API with a free tier.
curl https://api.vatnode.dev/v1/vat/FI17156132 \
-H "Authorization: Bearer vat_live_..."
# → { "valid": true, "companyName": "Suomen Pehmeä Ikkuna Oy" }MIT
If you find this useful, a ⭐ on GitHub is appreciated.