A curated directory of developer tools, software, services & hardware made in Europe.
The repository is a declarative directory: the source of truth lives in data/ as
JSON. A zero-dependency static site generator consumes that data and renders a static
site with a dynamic front-end (live search, multi-facet filters, sort, and a
24-EU-language switcher) into dist/.
A community-driven list of software, SaaS, hardware, and cloud services built by European companies β privacy-first, GDPR-native, and keeping your data on this side of the Atlantic.
data/ β source of truth (declarative JSON)
directory.json β taxonomy: list of categories + their files
schema.json β entry schema (JSON Schema 2020-12)
top-european-projects.json
categories/*.json β one file per category, edited by curators
src/
templates/landing.html β landing page template ( placeholders)
templates/category.html β directory page template (search/filter/sort UI)
styles.css β full stylesheet (EU-themed dark UI)
client.mjs β browser ES module: i18n switcher + directory engine
i18n.json β 24 EU languages (extracted from legacy page + UI keys)
scripts/
build.mjs β static site generator β dist/
serve.mjs β tiny zero-dep dev server
extract-i18n.mjs β one-off: regenerate src/i18n.json from legacy page
.github/workflows/deploy.yml β build + deploy dist/ to GitHub Pages
dist/ β generated site (gitignored, built on push)
The data is the source of truth; the site is a consumer of it
(see DIRECTORY_BEST_PRACTICE_PATTERNS.md, pattern 10).
Requires Node.js 20+.
npm run build # render data/ β dist/ (landing + one page per category + all.html)
npm run serve # serve dist/ at http://localhost:4321
npm run dev # rebuild on data/src/scripts change + serve
npm start # build && serve
Edit the declarative JSON β no HTML to touch.
data/categories/<category>.json (see data/schema.json for the shape).data/directory.json and create data/categories/<id>.json.npm run build (or it auto-rebuilds under npm run dev).Every entry should include: name, category, homepage, description,
origin.country, origin.evidence, tags, useCases, deployment,
pricingModel, license, isOpenSource, curation.confidence, sources
(see data/README.md for lookup examples).
Each category page (and /all.html) ships with a sticky toolbar offering:
src/i18n.json).The page initially renders skeleton cards, fetches /assets/directory.json
(the bundled data), then hydrates the grid β all client-side, no framework.
Pushes to main trigger .github/workflows/deploy.yml, which runs npm run build
and deploys dist/ to GitHub Pages via actions/deploy-pages.
In the repo settings β Pages β Source, select GitHub Actions (not βDeploy
from a branchβ). The CNAME (custom domain madeineurope.dev) is copied into
dist/ automatically by the build.
The 24-language strings were extracted from the legacy hand-written landing page
into src/i18n.json. Directory UI strings are added there too. If you need to
re-extract from an updated legacy file:
node scripts/extract-i18n.mjs
European tools arenβt just about compliance. Theyβre about choosing where your data lives and who has access to it. GDPR by default, lower latency for EU users, and supporting local tech ecosystems.
MIT