Files
next.js/docs/03-architecture/supported-browsers.mdx
T
JosephandGitHub 7ec73949fc docs: clarify instrumentation-client polyfill loading and hydration timing (#95988)
The `instrumentation-client` Polyfills docs recommended a conditional
dynamic `import().then()` to load a polyfill. That import is
fire-and-forget: Next.js loads this file synchronously and does not
await it before hydration, so the polyfill can install after components
have already run (see #83905).

- In "Execution timing" mention that only synchronous top-level code
completes before hydration. Call out that a conditional `import()` here
is not awaited, and cross-reference `supported-browsers` for
load-on-demand strategies and the built-in baseline.

- In **`supported-browsers.mdx`**, "fix" the `Conditionally loading
polyfills` example to `await import()` instead of a floating `.then()`,
otherwise, a reader needs to put their code within the `.then` chain of
the polyfill load.

Closes:
https://linear.app/vercel/issue/DOC-6506/revisit-polyfills-with-instrumentation-client
2026-07-28 15:44:03 -04:00

126 lines
4.5 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Supported Browsers
description: Browser support and which JavaScript features are supported by Next.js.
---
Next.js supports **modern browsers** with zero configuration.
- Chrome 111+
- Edge 111+
- Firefox 111+
- Safari 16.4+
## Browserslist
If you would like to target specific browsers or features, Next.js supports [Browserslist](https://browsersl.ist) configuration in your `package.json` file. Next.js uses the following Browserslist configuration by default:
```json filename="package.json"
{
"browserslist": ["chrome 111", "edge 111", "firefox 111", "safari 16.4"]
}
```
## Polyfills
We inject [widely used polyfills](https://github.com/vercel/next.js/blob/canary/packages/next-polyfill-nomodule/src/index.js), including:
- [**fetch()**](https://developer.mozilla.org/docs/Web/API/Fetch_API) — Replacing: `whatwg-fetch` and `unfetch`.
- [**URL**](https://developer.mozilla.org/docs/Web/API/URL) — Replacing: the [`url` package (Node.js API)](https://nodejs.org/api/url.html).
- [**Object.assign()**](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) — Replacing: `object-assign`, `object.assign`, and `core-js/object/assign`.
If any of your dependencies include these polyfills, they’ll be eliminated automatically from the production build to avoid duplication.
In addition, to reduce bundle size, Next.js will only load these polyfills for browsers that require them. The majority of the web traffic globally will not download these polyfills.
### Custom Polyfills
If your own code or any external npm dependencies require features not supported by your target browsers (such as IE 11), you need to add polyfills yourself.
#### In App Router
To include polyfills, you can import them into the [`instrumentation-client.js` file](/docs/app/api-reference/file-conventions/instrumentation-client).
```ts filename="instrumentation-client.ts"
import './polyfills'
```
#### In Pages Router
In this case, you should add a top-level import for the **specific polyfill** you need in your [Custom `<App>`](/docs/pages/building-your-application/routing/custom-app) or the individual component.
```tsx filename="pages/_app.tsx" switcher
import './polyfills'
import type { AppProps } from 'next/app'
export default function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}
```
```jsx filename="pages/_app.jsx" switcher
import './polyfills'
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
```
#### Conditionally loading polyfills
The best approach is to isolate unsupported features to specific UI sections and conditionally load the polyfill if needed.
```ts filename="hooks/analytics.ts" switcher
import { useCallback } from 'react'
export const useAnalytics = () => {
const tracker = useCallback(async (data: unknown) => {
if (!('structuredClone' in globalThis)) {
const mod = await import('polyfills/structured-clone')
globalThis.structuredClone = mod.default
}
/* Do some work that uses structured clone */
}, [])
return tracker
}
```
```js filename="hooks/analytics.js" switcher
import { useCallback } from 'react'
export const useAnalytics = () => {
const tracker = useCallback(async (data) => {
if (!('structuredClone' in globalThis)) {
const mod = await import('polyfills/structured-clone')
globalThis.structuredClone = mod.default
}
/* Do some work that uses structured clone */
}, [])
return tracker
}
```
## JavaScript Language Features
Next.js allows you to use the latest JavaScript features out of the box. In addition to [ES6 features](https://github.com/lukehoban/es6features), Next.js also supports:
- [Async/await](https://github.com/tc39/ecmascript-asyncawait) (ES2017)
- [Object Rest/Spread Properties](https://github.com/tc39/proposal-object-rest-spread) (ES2018)
- [Dynamic `import()`](https://github.com/tc39/proposal-dynamic-import) (ES2020)
- [Optional Chaining](https://github.com/tc39/proposal-optional-chaining) (ES2020)
- [Nullish Coalescing](https://github.com/tc39/proposal-nullish-coalescing) (ES2020)
- [Class Fields](https://github.com/tc39/proposal-class-fields) and [Static Properties](https://github.com/tc39/proposal-static-class-features) (ES2022)
- and more!
### TypeScript Features
Next.js has built-in TypeScript support. [Learn more here](/docs/pages/api-reference/config/typescript).
### Customizing Babel Config (Advanced)
You can customize babel configuration. [Learn more here](/docs/pages/guides/babel).