HomeSandboxShowcaseAppDocBlog
    • EnglishEnglish
      EN
    • русскийRussian
      RU
    • 日本語Japanese
      JA
    • françaisFrench
      FR
    • 한국어Korean
      KO
    • 中文Chinese
      ZH
    • españolSpanish
      ES
    • DeutschGerman
      DE
    • العربيةArabic
      AR
    • italianoItalian
      IT
    • British EnglishBritish English
      EN-GB
    • portuguêsPortuguese
      PT
    • हिन्दीHindi
      HI
    • TürkçeTurkish
      TR
    • polskiPolish
      PL
    • IndonesiaIndonesian
      ID
    • Tiếng ViệtVietnamese
      VI
    • українськаUkrainian
      UK
    /
    Filter docs by framework
    Alt+←
    Why Intlayer ?
    Get Started
    Concept
    • How Intlayer Works
    • Configuration
    • TestFillBuildWatchExtractLoginPushPullConfigurationListVersionEditorLiveDebugDoc ReviewDoc TranslateSDK
    • Visual Editor
    • CMS
    • CI/CD Integration
    • TranslationPluralEnumerationConditionGenderInsertionFileNestingMarkdownHTMLFunction Fetching
    • Per Locale File
    • Compiler
    • Auto Fill
    • Testing
    • Bundle Optimization
    Environment
    • Next.js 14 and App Router
      Next.js 15
      Next.js no locale path
      Next.js and Page Router
      Compiler
    • Tanstack Start Solid
    • Astro and React
      Astro and Svelte
      Astro and Vue
      Astro and Solid
      Astro and Preact
      Astro and Lit
      Astro and Vanilla JS
    • React Router v7
      React Router v7 (fs-routes)
      Compiler
    • Nuxt and Vue
    • Vite and Solid
    • SvelteKit
    • Vite and Preact
    • Vite and Vanilla JS
    • Vite and Lit
    • Angular 19 (Webpack)
      Analog
    • React CRA
    • React Native and Expo
    • Express.js
      NestJS
      Fastify
      Hono
      Adonis
    • Lynx and React
    Plugins
    • JSON
    • gettext (.po)
    VS Code Extension
    Agent
    • MCP Server
    • Agent skills
    Releases
    • v8
    • v7
    • v6
    Benchmark
    • Next.js
    • TanStack
    • Vue
    • Solid
    • Svelte
    Blog
    Ask a question
    1. Documentation
    2. Concept
    3. Bundle optimization
    Creation:2025-11-25Last update:2026-04-08
    Reference this doc to your favorite AI assistant
    ChatGPT
    Claude
    DeepSeek
    Google AI mode
    Gemini
    Perplexity
    Mistral
    Grok

    Ask your question and get a summary of the document by referencing this page and the AI provider of your choice

    Version History

    1. "Add `minify` and `purge` options to the build configuration"
      v8.7.04/8/2026
    Edit this doc

    If you have an idea for improving this documentation, please feel free to contribute by submitting a pull request on GitHub.

    GitHub link to the documentation
    Copy

    Copy doc Markdown to clipboard

    Optimizing i18n Bundle Size & Performance

    One of the most common challenges with traditional i18n solutions relying on JSON files is managing content size. If developers do not manually separate content into namespaces, users often end up downloading translations for every page and potentially every language just to view a single page.

    For example, an application with 10 pages translated into 10 languages might result in a user downloading the content of 100 pages, even though they only need one (the current page in the current language). This leads to wasted bandwidth and slower load times.

    Intlayer solves this problem through build-time optimization. It analyzes your code to detect which dictionaries are actually used per component and reinjects only the necessary content into your bundle.

    Table of Contents

    Scan your bundle

    Analyzing your bundle is the first step in identifying "heavy" JSON files and code-splitting opportunities. These tools generate a visual treemap of your application's compiled code, allowing you to see exactly which libraries are consuming the most space.

    Vite / Rollup

    Vite uses Rollup under the hood. The rollup-plugin-visualizer generates an interactive HTML file showing the size of every module in your graph.

    bash
    Copy code

    Copy the code to the clipboard

    npm install -D rollup-plugin-visualizer
    vite.config.ts
    Copy code

    Copy the code to the clipboard

    import { defineConfig } from "vite";import { visualizer } from "rollup-plugin-visualizer";export default defineConfig({ plugins: [   visualizer({     open: true, // Automatically open the report in your browser     filename: "stats.html",     gzipSize: true,     brotliSize: true,   }), ],});

    Next.js (Turbopack)

    For projects using the App Router and Turbopack, Next.js provides a built-in experimental analyzer that requires no extra dependencies.

    bash
    Copy code

    Copy the code to the clipboard

    npx next experimental-analyze

    Next.js (Webpack)

    If you are using the default Webpack bundler in Next.js, use the official bundle analyzer. Trigger it by setting an environment variable during your build.

    bash
    Copy code

    Copy the code to the clipboard

    npm install -D @next/bundle-analyzer
    next.config.js
    Copy code

    Copy the code to the clipboard

    const withBundleAnalyzer = require("@next/bundle-analyzer")({ enabled: process.env.ANALYZE === "true",});module.exports = withBundleAnalyzer({ // Your Next.js config});

    Usage:

    bash
    Copy code

    Copy the code to the clipboard

    ANALYZE=true npm run build

    Standard Webpack

    For Create React App (ejected), Angular, or custom Webpack setups, use the industry-standard webpack-bundle-analyzer.

    bash
    Copy code

    Copy the code to the clipboard

    npm install -D webpack-bundle-analyzer
    Copy code

    Copy the code to the clipboard

    import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";export default { plugins: [   new BundleAnalyzerPlugin({     analyzerMode: "static",     reportFilename: "bundle-analyzer.html",     openAnalyzer: false,   }), ],};

    How It Works

    Intlayer uses a per-component approach. Unlike global JSON files, your content is defined alongside or within your components. During the build process, Intlayer:

    1. Analyzes your code to find useIntlayer calls.
    2. Builds the corresponding dictionary content.
    3. Replaces the useIntlayer call with optimized code based on your configuration.

    This ensures that:

    • If a component is not imported, its content is not included in the bundle (Dead Code Elimination).
    • If a component is lazy-loaded, its content is also lazy-loaded.

    Setup by Platform

    Next.js

    Next.js requires the @intlayer/swc plugin to handle the transformation, as Next.js uses SWC for builds.

    This plugin is not installed by default because SWC plugins are still experimental for Next.js. It may change in the future.
    bash
    Copy code

    Copy the code to the clipboard

    npm install -D @intlayer/swc

    Once Installed. Intlayer will automatically detect and use the plugin.

    Vite

    Vite uses @intlayer/babel plugin which is included as dependency of vite-intlayer. The optimization is enabled by default. Nothing else to do.

    Webpack

    To enable bundle optimization with Intlayer on Webpack, you need to install and configure the appropriate Babel (@intlayer/babel) or SWC (@intlayer/swc) plugin.

    bash
    Copy code

    Copy the code to the clipboard

    npm install -D @intlayer/babel
    babel.config.js
    Copy code

    Copy the code to the clipboard

    const { getOptimizePluginOptions, intlayerOptimizeBabelPlugin,} = require("@intlayer/babel");module.exports = { plugins: [[intlayerOptimizeBabelPlugin, getOptimizePluginOptions()]],};

    Configuration

    You can control how Intlayer optimizes your bundle via the build property in your intlayer.config.ts.

    intlayer.config.ts
    Copy code

    Copy the code to the clipboard

    import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [Locales.ENGLISH, Locales.FRENCH],    defaultLocale: Locales.ENGLISH,  },  dictionary: {    importMode: "dynamic",  },  build: {    /**     * Minify the dictionaries to reduce the bundle size.     */     minify: true;    /**     * Purge the unused keys in a dictionaries     */     purge: true;    /**     * Indicates if the build should check TypeScript types     */    checkTypes: false;  },};export default config;
    Keeping the default option for optimize is recommended in the most majority of cases.
    See doc configuration for more details: Configuration

    Build Options

    The following options are available under the build configuration object:

    Show all table content

    Open the table in a modal to view all data content clearly

    Property Type Default Description
    optimize boolean undefined Controls whether build optimization is enabled. If true, Intlayer replaces dictionary calls with optimized injects. If false, optimization is disabled. Ideally set to true in production.
    minify boolean false Whether to minify the dictionaries to reduce the bundle size.
    purge boolean false Whether to purge the unused keys in dictionaries.

    Minification

    Minifying dictionaries removes unnecessary whitespace, comments, and reduces the size of the JSON content. This is especially useful for large dictionaries.

    intlayer.config.ts
    Copy code

    Copy the code to the clipboard

    import type { IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  build: {    minify: true,  },};export default config;
    Note: Minification is ignored if optimize is disabled or if the Visual Editor is enabled (as the editor needs the full content to allow editing).

    Purging

    Purging ensures that only the keys actually used in your code are included in the final dictionary bundle. This can significantly reduce the size of your bundle if you have large dictionaries with many keys that are not used in every part of your application.

    intlayer.config.ts
    Copy code

    Copy the code to the clipboard

    import type { IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  build: {    purge: true,  },};export default config;
    Note: Purging is ignored if optimize is disabled.

    Import Mode

    For large applications, including several pages and locales, your JSON can represent a significant part of your bundle size. Intlayer allows you to control how dictionaries are loaded using the importMode option.

    Global definition

    The import mode can be defined by default globally in your intlayer.config.ts file.

    intlayer.config.ts
    Copy code

    Copy the code to the clipboard

    import type { IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  dictionary: {    importMode: "dynamic", // Default is 'static'  },};export default config;

    Per dictionary fine-grained definition

    As well as for each dictionaries in your .content.{{ts|tsx|js|jsx|mjs|cjs|json|jsonc|json5}} files.

    ts
    Copy code

    Copy the code to the clipboard

    import { type Dictionary, t } from "intlayer";const appContent: Dictionary = {  key: "app",  importMode: "dynamic", // Override the default import mode  content: {    // ...  },};export default appContent;
    Show all table content

    Open the table in a modal to view all data content clearly

    Property Type Default Description
    importMode 'static', 'dynamic', 'fetch' 'static' Deprecated: Use dictionary.importMode instead. Determines how dictionaries are loaded (see details below).

    The importMode setting dictates how the dictionary content is injected into your component. You can define it globally in the intlayer.config.ts file under the dictionary object, or you can overwrite it for a specific dictionary in its .content.ts file.

    1. Static Mode (default)

    In static mode, Intlayer replaces useIntlayer with useDictionary and injects the dictionary directly into the JavaScript bundle.

    • Pros: Instant rendering (synchronous), zero extra network requests during hydration.
    • Cons: The bundle includes translations for all available languages for that specific component.
    • Best for: Single Page Applications (SPA).

    Transformed Code Example:

    tsx
    Copy code

    Copy the code to the clipboard

    // Your codeconst content = useIntlayer("my-key");// Optimized code illustration after transformation (Static)// This is only for illustration purposes, the actual code will be different for optimization reasonsconst content = useDictionary({  key: "my-key",  content: {    nodeType: "translation",    translation: {      en: "My title",      fr: "Mon titre",    },  },});

    2. Dynamic Mode

    In dynamic mode, Intlayer replaces useIntlayer with useDictionaryAsync. This uses import() (Suspense-like mechanism) to lazy-load specifically the JSON for the current locale.

    • Pros: Locale-level tree shaking. A user viewing the English version will only download the English dictionary. The French dictionary is never loaded.
    • Cons: Triggers a network request (asset fetch) per component during hydration.
    • Best for: Large text blocks, articles, or applications supporting many languages where bundle size is critical.

    Transformed Code Example:

    tsx
    Copy code

    Copy the code to the clipboard

    // Your codeconst content = useIntlayer("my-key");// Optimized code illustration after transformation (Dynamic)// This is only for illustration purposes, the actual code will be different for optimization reasonsconst content = useDictionaryAsync({  en: () =>    import(".intlayer/dynamic_dictionary/my-key/en.json").then(      (mod) => mod.default    ),  fr: () =>    import(".intlayer/dynamic_dictionary/my-key/fr.json").then(      (mod) => mod.default    ),});
    When using importMode: 'dynamic', if you have 100 components using useIntlayer on a single page, the browser will attempt 100 separate fetches. To avoid this "waterfall" of requests, group content into fewer .content files (e.g., one dictionary per page section) rather than one per atom component. You can also use multiple .content files using the same key. Intlayer will merge them into a single dictionary.

    3. Fetch Mode

    Behaves similarly to Dynamic mode but attempts to fetch dictionaries from the Intlayer Live Sync API first. If the API call fails or the content is not marked for live updates, it falls back to the dynamic import.

    Transformed Code Example:

    tsx
    Copy code

    Copy the code to the clipboard

    // Your codeconst content = useIntlayer("my-key");// Optimized code illustration (Fetch)const content = useDictionaryAsync({  en: () =>    fetch("https://intlayer.my-domain.com/dictionary/my-key/en").then((res) =>      res.json()    ),  fr: () =>    fetch("https://intlayer.my-domain.com/dictionary/my-key/fr").then((res) =>      res.json()    ),});
    See CMS documentation for more details: CMS
    In fetch mode, purge and minification can't be used.

    Summary: Static vs Dynamic

    Show all table content

    Open the table in a modal to view all data content clearly

    Feature Static Mode Dynamic Mode
    JS Bundle Size Larger (includes all langs for the component) Smallest (only code, no content)
    Initial Load Instant (Content is in bundle) Slight delay (Fetches JSON)
    Network Requests 0 extra requests 1 request per dictionary key
    Tree Shaking Component-level Component-level + Locale-level
    Best Use Case UI Components, Small Apps Pages with much text, Many Languages
    Testing
    Next.js
    Alt+→

    In this page

      Discussions are anonymous and regularly reviewed to address common issues. Feel free to share feature ideas, feedback on the documentation, or anything related to Intlayer, we use this input to shape our roadmap and improve the product.

      npm install -D rollup-plugin-visualizer
      import { defineConfig } from "vite";import { visualizer } from "rollup-plugin-visualizer";export default defineConfig({ plugins: [   visualizer({     open: true, // Automatically open the report in your browser     filename: "stats.html",     gzipSize: true,     brotliSize: true,   }), ],});
      npx next experimental-analyze
      npm install -D @next/bundle-analyzer
      const withBundleAnalyzer = require("@next/bundle-analyzer")({ enabled: process.env.ANALYZE === "true",});module.exports = withBundleAnalyzer({ // Your Next.js config});
      ANALYZE=true npm run build
      npm install -D webpack-bundle-analyzer
      import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";export default { plugins: [   new BundleAnalyzerPlugin({     analyzerMode: "static",     reportFilename: "bundle-analyzer.html",     openAnalyzer: false,   }), ],};
      npm install -D @intlayer/swc
      npm install -D @intlayer/babel
      const { getOptimizePluginOptions, intlayerOptimizeBabelPlugin,} = require("@intlayer/babel");module.exports = { plugins: [[intlayerOptimizeBabelPlugin, getOptimizePluginOptions()]],};
      import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [Locales.ENGLISH, Locales.FRENCH],    defaultLocale: Locales.ENGLISH,  },  dictionary: {    importMode: "dynamic",  },  build: {    /**     * Minify the dictionaries to reduce the bundle size.     */     minify: true;    /**     * Purge the unused keys in a dictionaries     */     purge: true;    /**     * Indicates if the build should check TypeScript types     */    checkTypes: false;  },};export default config;
      import type { IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  build: {    minify: true,  },};export default config;
      import type { IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  build: {    purge: true,  },};export default config;
      import type { IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  dictionary: {    importMode: "dynamic", // Default is 'static'  },};export default config;
      import { type Dictionary, t } from "intlayer";const appContent: Dictionary = {  key: "app",  importMode: "dynamic", // Override the default import mode  content: {    // ...  },};export default appContent;
      // Your codeconst content = useIntlayer("my-key");// Optimized code illustration after transformation (Static)// This is only for illustration purposes, the actual code will be different for optimization reasonsconst content = useDictionary({  key: "my-key",  content: {    nodeType: "translation",    translation: {      en: "My title",      fr: "Mon titre",    },  },});
      // Your codeconst content = useIntlayer("my-key");// Optimized code illustration after transformation (Dynamic)// This is only for illustration purposes, the actual code will be different for optimization reasonsconst content = useDictionaryAsync({  en: () =>    import(".intlayer/dynamic_dictionary/my-key/en.json").then(      (mod) => mod.default    ),  fr: () =>    import(".intlayer/dynamic_dictionary/my-key/fr.json").then(      (mod) => mod.default    ),});
      // Your codeconst content = useIntlayer("my-key");// Optimized code illustration (Fetch)const content = useDictionaryAsync({  en: () =>    fetch("https://intlayer.my-domain.com/dictionary/my-key/en").then((res) =>      res.json()    ),  fr: () =>    fetch("https://intlayer.my-domain.com/dictionary/my-key/fr").then((res) =>      res.json()    ),});