Benchmark
This benchmark compares the transfer size of Paraglide JS (a compiler-based i18n library) against i18next (a runtime-based library).
Key Takeaways
Paraglide ships 3-10x smaller bundles than runtime libraries
In typical scenarios, Paraglide ships 47-144 KB vs i18next's 205-422 KB.
Tree-shaking makes Paraglide immune to total message count
Runtime libraries ship all messages in a namespace, even unused ones. Paraglide only ships messages you actually use on a page.
Paraglide's bundle size stays constant regardless of how many messages exist in your project—unused messages are tree-shaken away at build time.
Runtime libraries like i18next rely on manual namespacing to reduce bundle size, but namespaces still ship all their messages whether used or not. This means developers must carefully split messages across namespaces, and even then, unused messages within a namespace are still shipped.
Why Paraglide ships smaller bundles
For a feature comparison, see the comparison table.
Interactive Benchmark
Explore the full benchmark data with different configurations:
Methodology
What is Being Tested
The benchmark creates a static website for each configuration (library variant, number of locales, messages per page, and namespace size). Each website is loaded in a headless browser, and the total transfer size is measured.
- Number of Locales: How does an i18n library scale with the number of locales?
- Number of used Messages: How does an i18n library scale with the number of messages that are used on a given page?
- Library Implementation Variants: Testing different implementation approaches:
- Paraglide:
default: Standard implementationexperimental-: Experimental implementation with per-locale splitting
- i18next:
http-backend: Using HTTP backend for loading translations
- Paraglide:
- Namespace Size: Testing how the total available messages in a namespace affects bundle size
Library modes
Each library is tested in different modes:
- Paraglide:
- default: Out of the box Paraglide JS with no additional compiler options.
: Mode with a compiler option that is being tested.
- i18next:
Limitations
Choosing the number of messages and namespace varies between projects
Some teams use per component namespacing while other teams have one namespace for their entire project. In cal.com's case, every component that uses i18n loads at least 3000 messages per locale.
To the point of the problem: Avoiding manual chunking of messages into namespaces is the benefit of Paraglide JS. The bundler tree-shakes all unused messages, making namespaces redundant.
Contributing
Contributions to improve the benchmark are welcome.
- adjust the build matrix in
build.config.ts - run
pnpm run benchto build the benchmark - run
pnpm run previewto preview the results


