react-intl is optimized for both runtime & compile time rendering. Below are a few guidelines you can follow if you have a strict performance budget.

Pre-compiling messages

You can also pre-compile all messages into AST using @formatjs/cli compile command and pass that into IntlProvider. This is especially faster since it saves us time parsing string into AST. The use cases for this support are:

  1. Server-side rendering or pre-compiling where you can cache the AST and don't have to pay compilation costs multiple time.
  2. Desktop apps using Electron or CEF where you can preload/precompile things in advanced before runtime.

react-intl without parser

Precompiling skips runtime parsing but does not remove the parser from your bundle. After precompiling all messages and defaultMessages, alias @formatjs/icu-messageformat-parser to @formatjs/icu-messageformat-parser/no-parser.js. This keeps AST formatting and throws if parsing is needed.

vite.config.js

export default {
  resolve: {
    alias: {
      '@formatjs/icu-messageformat-parser':
        '@formatjs/icu-messageformat-parser/no-parser.js',
    },
  },
}

webpack.config.js

module.exports = {
  //...
  resolve: {
    alias: {
      '@formatjs/icu-messageformat-parser':
        '@formatjs/icu-messageformat-parser/no-parser.js',
    },
  },
}

rollup.config.js

module.exports = {
  //...
  plugins: [
    alias({
      entries: {
        '@formatjs/icu-messageformat-parser':
          '@formatjs/icu-messageformat-parser/no-parser.js',
      },
    }),
  ],
}

In the future, we'll gear towards making this the default behavior.

Imperative APIs

Imperative APIs (e.g formatMessage...) are generally faster than Formatted component since it does not create extra ReactElement nodes. They should have the exact same capabilities as Formatted components.

More examples

Head over to https://github.com/formatjs/formatjs/tree/main/packages/react-intl/examples for more examples on how to use our libraries.