Skip to content

Topic · Performance

Extraction should not be the slow part of your build.

Extraction reads your entire source tree, parses it, and reconciles what it finds against every catalog you ship. Most tooling does that in JavaScript, once per build and again on every pre-commit hook. On a real codebase that is seconds of waiting, several times an hour, for a step nobody thinks about until it hurts.

01 — The problem

Where the time actually goes

Extraction is compiler work: parse every file, find the messages, understand their structure, then merge the result into existing catalogs without losing translations. Doing that in JavaScript means paying parse costs in the slowest part of the toolchain, on a workload that grows with your repository rather than with your feature.

02 — The approach

One native engine, doing all of it

Parsing, extraction, catalog merging, audits and ICU diagnostics run in a single Rust core rather than across a stack of JavaScript plugins.

Native parsing, not convention scanning

Messages are found by parsing your source, so the result is exact rather than heuristic — and the parse happens in native code rather than in the JavaScript layer that has to be loaded and warmed first.

Merging is part of the same pass

The benchmark measures the workflow you actually run — extract and update — not extraction alone. Catalog-aware tools also reconcile existing per-locale catalogs, which is where a naive implementation loses translations or spends its time.

Consistent semantics as a side effect

The useful consequence is not only speed. Because one engine owns catalog semantics, an audit result cannot depend on which adapter asked for it — the same rules apply from the CLI, the Vite plugin and the Next.js plugin.

03 — Evidence

The number, and how to reproduce it

Median of 7 runs on a realistic corpus — 1,500 files (750 with i18n), ~400k lines, 6,000 messages — with the same semantic validation applied to every tool. The report and the harness are checked into the repository, and the site build fails if these figures drift from it.

Checked result ledger

Realistic corpus — 1,500 files across ~400k lines, 6,000 messages (median of 7 runs)

Methodology →
Rounded workflow times and relative factors for 1,500 files (750 with i18n), ~400k lines, 6,000 messages. Exact values are available in the checked benchmark report.
WorkflowResultRelative time
Palamedesextract + catalog update47–73 ms*
React Intlextraction only · narrower scope424 ms
Linguiextract + catalog update2.2 s30×
fbteecollect + two-catalog update · two CLI commands7.3 s100×
General Translationextract + catalog update5.1 s70×
i18next-cliextract + catalog update5.8 s80×

* 47 ms is Palamedes on a cached re-run after 5 changed source files; 73 ms is the cold workflow result. No speedup factor is calculated for the non-comparable cached run. Cache details →

Times are rounded to display precision and relative factors are rounded down. Exact medians remain in the checked report. Machine-local run: darwin/arm64, Node v24.19.0, 2026-08-14, median of 7 runs.

Read the method and re-run it

04 — Questions

Questions people actually ask

Answered here rather than buried three pages into the documentation.

How was this measured?
Median of seven runs on a realistic corpus of 1,500 files (750 with i18n), ~400k lines, 6,000 messages, one machine-local run, with the same logical message inventory and the same semantic validation for every tool. The harness and the full report are in the repository so you can re-run both.
Will I see the same numbers?
Almost certainly not — these are machine-local figures from one machine, not an average. Your hardware will differ. The ratios between tools are the signal, and running the harness on your own hardware is the honest way to check them.
Does the benchmark include catalog merging?
Yes, and that matters for reading it fairly. The catalog-aware tools extract and then update existing per-locale catalogs. The React Intl extraction workflow writes a single aggregated message file instead, so it is doing less work in the same row.
Which tools are covered?
Lingui, React Intl, fbtee, i18next-cli and General Translation. Tools the harness has not measured are not given a speed claim anywhere on this site, because a guess dressed as a benchmark is worse than no number.
Does faster extraction mean a smaller bundle?
No, and the two should not be conflated. This is build-time performance. On runtime bundle size a zero-runtime compiler like Paraglide beats a runtime layer by construction, and we say so on the page comparing the two.

05 — Keep reading

Related pages

Every claim on this page is checked into the repository.