What is a browser target and why frontend builds are not the same for every browser

BasicsFrontendJavaScriptBuild

Browser target diagram: one frontend build prepares different compatibility levels for modern and older browsers

Hook

A browser target answers a simple but expensive question: which browsers are we actually building this frontend for? If nobody answers it, the build tool decides for you, and users with a slightly older browser may get a blank page instead of the site.

Problem / Context

Modern JavaScript and CSS move faster than the browsers real people keep on their devices. Everything may work on a developer’s laptop in the latest Chrome, while part of the audience opens the site in Safari on an older iPhone, Android WebView inside another app, or a corporate browser that updates once every few ages.

A frontend build has to decide which code can stay modern and which code should go through transpilation. New syntax may be pleasant for the team, but browsers do not understand every modern feature at the same time. The build tool looks at the target and decides how careful the output should be.

The problem is that browser target often hides somewhere in configuration and only gets attention after something breaks. In Vite it may be build.target, in some projects it is a browserslist field in package.json, and in older stacks it may be a mix of Babel, Autoprefixer, and separate legacy plugins. If nobody knows which target is active, the team is not managing compatibility. It is just hoping.

Why it matters

Browser target affects several things at once.

First, stability. If the build leaves syntax that the minimum browser does not support, the page can crash before the user sees the interface. That kind of bug is painful because it often does not reproduce on the developer’s machine.

Second, bundle size. The older the browsers you support, the more transformations and helper code you may need. This does not mean old browsers must always be cut off. It means browser support should be a deliberate decision.

Third, CSS. Prefixes, new selectors, modern units, and layout features also have support boundaries. If the target is only considered for JavaScript, you can accidentally ship clean code and a messy layout.

Fourth, testing. You cannot honestly say “we support Safari 16” if nobody opened preview in Safari 16 or checked compatibility with the relevant tools.

Illustration: one goal, different output

Think of the build tool as a translator between the development team and the user’s browsers. On the left there is modern code that is pleasant to write. On the right there are browsers with different levels of support. The browser target tells the translator: “This is the minimum audience. Do not go below it.”

If the target is modern, the output can stay smaller and closer to the source code. If the target is older, the build must be more cautious: transform part of the syntax, add a polyfill, or warn that a certain feature needs a separate decision.

Important detail: a target does not make the impossible possible. If a browser does not have a platform feature, the build tool cannot always create it out of thin air. Sometimes you need a polyfill, sometimes a fallback in the code, and sometimes an honest decision not to support that browser.

How to do it

1. Find where the target is defined

Start with package.json and build configuration. In Vite you may see something like this:

// vite.config.js
export default {
  build: {
    target: "es2020"
  }
};

This means the build is aimed at a level of support close to ES2020. Do not copy this blindly. Another product may need a different target.

In some projects the browser list lives in package.json:

{
  "browserslist": [
    "last 2 Chrome versions",
    "last 2 Firefox versions",
    "Safari >= 16"
  ]
}

Browserslist can be read by different tools. So it is important to understand not only what is written, but also which part of your stack actually uses it.

2. Translate the product requirement into a technical target

A bad target sounds like: “support everything.” A good target is specific: “support the last two versions of major browsers and Safari from the version that matches our traffic data.”

If you have analytics, check the real browsers your users bring. If you do not, write down a reasonable assumption and the date when it should be reviewed. The only thing worse than a wrong target is a target nobody can explain.

3. Run the production build and read the warnings

The command is usually familiar:

npm run build

After that, do not ignore warnings. The build tool may directly tell you that a feature cannot be transformed for the chosen target or that a CSS feature has limited support. A warning is not noise. It is an early signal that is cheaper to investigate now than after release.

4. Check preview in the minimum browser

If you claim support for a minimum browser, open that browser. Not only the latest Chrome on a developer machine. Check the page startup, navigation, forms, modals, lazy loading, checkout, or any other critical path.

For a small site, a short manual smoke test may be enough. For an important product, add it to CI or at least to the release checklist.

5. Do not solve everything with polyfills

A polyfill is useful when it closes a real compatibility gap. But if you add everything “just in case,” users receive heavier JavaScript and the team receives harder debugging. Define the target first, then check which exact features are still missing.

Anti-patterns

  • leaving the target at the default and not knowing what the default means;
  • copying browserslist from another project without matching it to your audience;
  • testing only in the latest Chrome;
  • supporting a very old legacy browser without estimating the cost;
  • adding a large polyfill set without a concrete reason;
  • confusing browser target with the Node.js version used by build scripts;
  • changing the target right before release without preview and smoke testing.

Conclusion / Action plan

Browser target is not a tiny technical setting. It is an agreement between the product, the team, and the real browsers users have. It defines how modern the output can be and what compatibility you promise.

What to do next:

  1. find the active target in the project;
  2. check whether it matches the real audience;
  3. run the production build and read the warnings;
  4. open preview in the minimum supported browsers;
  5. document the decision so the next developer does not have to become an archaeologist.

Official sources:

Quick checklist

  • Find where the project defines its browser target: build.target, browserslist, or framework settings.
  • Compare the target with the site's real audience, not with a random example from the internet.
  • Run the production build and read warnings about unsupported syntax or CSS.
  • Open preview in the minimum browsers that are claimed as supported.
  • Record the decision in README or release documentation.

Prompt Pack: audit browser target before release

Help audit the browser target in a frontend project before release. Input data: - framework and build tool: Vite, Astro, React, Vue, SvelteKit, Webpack, or another stack; - current build tool configuration; - package.json with browserslist or build.target; - the browsers that actually matter for the audience; - production build errors or warnings; - whether old Safari, Android WebView, or corporate browsers must be supported. Return: 1. which browser target is effectively active now; 2. whether it matches the real audience; 3. which modern features may break; 4. whether polyfills or a separate legacy build are needed; 5. a short verification plan for CI, preview, and real browsers. Response format: conclusion, risks, recommended target, config changes, testing checklist.