<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jan-Hendrik Kummert</title>
    <description>The latest articles on DEV Community by Jan-Hendrik Kummert (@stmhamburg).</description>
    <link>https://dev.to/stmhamburg</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3931750%2F384cae83-2b28-4a92-a358-1108aa26c39a.jpg</url>
      <title>DEV Community: Jan-Hendrik Kummert</title>
      <link>https://dev.to/stmhamburg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stmhamburg"/>
    <language>en</language>
    <item>
      <title>Why we open-sourced our internal EU VAT sync for Magento 2</title>
      <dc:creator>Jan-Hendrik Kummert</dc:creator>
      <pubDate>Thu, 14 May 2026 17:54:09 +0000</pubDate>
      <link>https://dev.to/stmhamburg/why-we-open-sourced-our-internal-eu-vat-sync-for-magento-2-28ga</link>
      <guid>https://dev.to/stmhamburg/why-we-open-sourced-our-internal-eu-vat-sync-for-magento-2-28ga</guid>
      <description>&lt;p&gt;We open-sourced our internal Magento 2 module that keeps EU VAT rates and Tax Rules in sync automatically. It's on Packagist as &lt;code&gt;storetown/module-tax-sync&lt;/code&gt;, MIT-licensed, and you can install it in one composer command. Here's why we did it and how it's built.&lt;/p&gt;

&lt;p&gt;The pain you didn't know you had&lt;/p&gt;

&lt;p&gt;If you run a Magento 2 store that ships across EU borders, you're probably maintaining ~50–60 tax rates by hand. Standard rate, reduced rate, sometimes a second reduced rate — for 27 EU countries, then Switzerland, the UK, and Norway if you care about those markets.&lt;/p&gt;

&lt;p&gt;You added them once during the shop setup. Then someone in Finland decided 25.5% was a better number than 24% (true story — happened in 2024). Then the Covid-era temporary reductions expired in five countries on different dates. Then Estonia announced a 24% standard rate effective 2025-07-01.&lt;/p&gt;

&lt;p&gt;Every time, an email lands in your finance team's inbox. Someone forwards it to dev. Dev edits &lt;code&gt;Stores → Tax Zones and Rates&lt;/code&gt;. If they edit the rate but forget to recompile the cache, frontend prices stay wrong for a week. If they remember the rate but forget to map it to the right Tax Rule, the change quietly never takes effect on any product.&lt;/p&gt;

&lt;p&gt;We've been running a small Magento 2 agency in Hamburg since 2014. We've watched this scenario play out across maybe a dozen client shops. So years ago we built a small internal module that does it for us. Last month we cleaned it up, ripped out the agency-specific bits, and put it on GitHub.&lt;/p&gt;

&lt;p&gt;What the module does&lt;/p&gt;

&lt;p&gt;&lt;a href="https://packagist.org/packages/storetown/module-tax-sync" rel="noopener noreferrer"&gt;&lt;code&gt;storetown/module-tax-sync&lt;/code&gt;&lt;/a&gt; — MIT, free, no telemetry, no signup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pulls all 27 EU VAT rates from the EU VAT Rates API (the official one) — standard and reduced&lt;/li&gt;
&lt;li&gt;Optional: CH, GB, NO (toggleable in admin)&lt;/li&gt;
&lt;li&gt;Auto-creates Tax Rules, not just Tax Rates. This is the unsexy but important bit. Most Magento extensions stop at Rates. Ours wires the Rates up to your existing customer tax classes and product tax classes so the change is actually applied.&lt;/li&gt;
&lt;li&gt;Runs on cron (daily/weekly/monthly — your call) and exposes manual sync via admin button + CLI&lt;/li&gt;
&lt;li&gt;Sends an email diff when rates change: which country, old rate → new rate&lt;/li&gt;
&lt;li&gt;Falls back to bundled static data if the EU VAT Rates API is unreachable, so you never get a broken sync&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require storetown/module-tax-sync
bin/magento module:enable Storetown_TaxSync
bin/magento setup:upgrade
bin/magento cache:flush
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Go to &lt;code&gt;Stores → Configuration → Storetown → EU Tax Rate Sync&lt;/code&gt;, set your sync frequency and notification email, click &lt;code&gt;Sync Now&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Architecture decisions worth knowing&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We picked the EU VAT Rates API over scraping&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There's an &lt;a href="https://taxation-customs.ec.europa.eu/" rel="noopener noreferrer"&gt;EU Commission API&lt;/a&gt; that returns official current rates as structured data. We use it. Some commercial Magento tax modules scrape national tax authority sites individually — that breaks the moment Germany redesigns their tax page (which happens roughly every 18 months). The EU API doesn't have that fragility.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tax Rules are auto-created with predictable names&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When the module creates a rate, it names it &lt;code&gt;DE-Standard&lt;/code&gt;, &lt;code&gt;DE-Reduced&lt;/code&gt;, &lt;code&gt;AT-Standard&lt;/code&gt;, etc. The Tax Rule that wraps it gets a matching predictable name. This is deliberate — it means a future you can grep for them, automate around them, and tell at a glance what's ours vs. what was set up manually.&lt;/p&gt;

&lt;p&gt;We don't touch any rate or rule whose name doesn't match our prefix. So your hand-crafted "DE-Special-Books-Reduced" rule survives any sync.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fallback data lives in the repo&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;Storetown/TaxSync/Data/fallback-rates.json&lt;/code&gt; is committed and updated with each release. If the EU API is down (it has been; once for 18 hours in late 2024), we fall back to this. Admins get a notification banner that says "API unreachable — using fallback from version X.Y.Z, last updated YYYY-MM-DD".&lt;/p&gt;

&lt;p&gt;This is the kind of detail that matters in production but is annoying to write. So we wrote it once.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CLI for CI/CD pipelines
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bin/magento tax:sync:run              &lt;span class="k"&gt;do &lt;/span&gt;a &lt;span class="nb"&gt;sync &lt;/span&gt;now
bin/magento tax:sync:status           last &lt;span class="nb"&gt;sync time&lt;/span&gt; + result
bin/magento tax:sync:run &lt;span class="nt"&gt;--dry-run&lt;/span&gt;    show what would change, don&lt;span class="s1"&gt;'t write
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plumb that into your deploy pipeline if you want — we run &lt;code&gt;--dry-run&lt;/code&gt; on staging before every prod deploy.&lt;/p&gt;

&lt;p&gt;Why open source, why now&lt;/p&gt;

&lt;p&gt;Three reasons.&lt;/p&gt;

&lt;p&gt;Reason one is honest self-interest: we're a small agency. Our four paid Magento extensions (checkout, B2B registration, attachments, surcharges) are what pay the bills. The tax-sync module was never going to be one of them — it's too narrow, the buyer pool is too small to support pricing. So either it stays internal and only our clients benefit, or it goes public and anyone running Magento 2 in the EU can use it.&lt;/p&gt;

&lt;p&gt;Reason two is that maintaining it inside the agency was actually a slight drag. Every client onboarding meant copying it from one repo to another, occasionally forgetting to update a deprecated method, hand-merging fixes back. Public + Composer + semver = those problems go away.&lt;/p&gt;

&lt;p&gt;Reason three is that we'd been quietly using the EU VAT Rates API for a year and seen exactly zero open-source Magento 2 modules using it. There are a couple of paid ones. There's a Drupal module. There's a Shopify app. For Magento 2 it's been DIY or pay €300/year. That gap shouldn't exist in 2026.&lt;/p&gt;

&lt;p&gt;What we'd love help with&lt;/p&gt;

&lt;p&gt;The roadmap is small and the issues are open:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More fallback data updates (PRs welcome — just bump &lt;code&gt;fallback-rates.json&lt;/code&gt; and tag a release)&lt;/li&gt;
&lt;li&gt;Multi-store config: if you run a multi-store with different default countries, we'd like to refine the per-store override logic&lt;/li&gt;
&lt;li&gt;An eventually-consistent "rate history" view in admin (we have the data, we don't yet have a UI)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repo + Issues: &lt;a href="https://github.com/storetown-media/stm-magento-2-eu-tax-rate-sync" rel="noopener noreferrer"&gt;https://github.com/storetown-media/stm-magento-2-eu-tax-rate-sync&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you're running Magento 2 in the EU and tired of hand-maintaining tax rates, give it a try. And if you're at a Magento agency that does the same hand-maintenance dance, tell us — we'd love to compare notes.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Storetown-Media is a small Magento 2 agency in Hamburg. We've been building Magento extensions since 2014. Our paid catalog is at &lt;a href="https://www.storetown-media.de/produkt-kategorie/downloads/magento-extensions/" rel="noopener noreferrer"&gt;storetown-media.de/produkt-kategorie/downloads/magento-extensions/&lt;/a&gt; — but this one's free.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>magneto</category>
      <category>php</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
