How to automate ttf-to-woff2 conversion in your build pipeline
- Step 1Add a Node script — Use Node 22's built-in fetch + the wawoff2 npm package: walk src/fonts/*.ttf, compress each, and write to public/fonts/*.woff2. The script runs in 10–30 seconds for typical design systems and is idempotent (skips files where the WOFF2 is newer than the TTF).
- Step 2Wire into prebuild — Add to package.json: "prebuild": "node scripts/woff2.mjs". Now every npm run build (including next build) runs WOFF2 generation first. Commit the generated WOFF2 files or .gitignore them depending on your team's preference.
- Step 3Add CI guard — In GitHub Actions, run the script and then git diff --exit-code public/fonts/. If a developer added a TTF without committing the matching WOFF2, the diff is non-empty and CI fails the PR with a clear error.
Frequently asked questions
Should I commit the generated WOFF2 files?+
Most teams do — it makes deploys reproducible and removes a build step. The downside is a slightly larger repo. If your fonts change rarely, commit; if they change weekly, .gitignore and rely on CI.
Can I convert at request time instead?+
Technically yes via a Cloudflare Worker or edge function, but it's wasteful — the same bytes get re-compressed millions of times. Build-time conversion is one-time work that benefits every visitor.
What about variable fonts in CI?+
Variable fonts compress especially well to WOFF2 — same pipeline, no special handling. The fvar table survives the round-trip, so the variable axes still work after compression.
How do I skip conversion in dev mode?+
Conditionally run the script: "prebuild": "node scripts/woff2.mjs". For dev (npm run dev), point @font-face directly at the TTF — Next.js dev mode is forgiving, and skipping the build step keeps the feedback loop fast.
Privacy first
Every JAD Font tool runs entirely in your browser using opentype.js and the wawoff2 WASM Brotli encoder. Your fonts never leave your device — verified by zero outbound network requests during processing.