A new method lands in the language, the documentation covers it, you use it. Then a visitor reports an error from a five-year-old device where that method does not exist.
A polyfill settles the case without giving up on modern code: it supplies the missing function, written in ordinary JavaScript.
Definition
A polyfill is a piece of code implementing a feature absent from the runtime, using only what that runtime already knows how to do. It installs itself once, at load time, and the rest of the program never has to ask the question again.
// Polyfill for Array.prototype.at
if (!Array.prototype.at) {
Array.prototype.at = function (index) {
const i = Math.trunc(index) || 0;
const position = i < 0 ? this.length + i : i;
if (position < 0 || position >= this.length) return undefined;
return this[position];
};
}
console.log([10, 20, 30].at(-1)); // 30The if condition is the heart of the technique: if the engine already provides the method, its own version is kept. A polyfill never replaces a native implementation, it only fills a hole.
Three neighboring ideas worth separating
| Term | What it addresses |
|---|---|
| Polyfill | A missing function, installed on the native object |
| Transpilation | Syntax the engine cannot parse, rewritten before shipping |
| Ponyfill | The same function, exported without touching the native object |
The third option is the most cautious: instead of modifying Array for the whole page, it exposes a function you import explicitly. No risk of clashing with a third-party library doing the same job differently.
Modifying a native object commits the entire page, including scripts you did not write. An approximate polyfill then produces bugs that are very hard to locate, since they surface far from the file at fault.
Do not load them for everyone
Shipping a batch of polyfills to every visitor punishes those whose browser needs none, which is to say most of them. Two approaches avoid that waste.
The first lets Babel inject only the polyfills matching the features actually used, based on the targeted browsers. The second tests for the feature at startup and loads the fallback only when needed, through import() (dynamic import).
Frequently asked questions
Should I write my own polyfills?
No, except to understand the mechanism. The edge cases are numerous, often counterintuitive, and a proven library already handles them. A homemade implementation drifting slightly from the specification is worse than no polyfill at all, because the error goes silent.
Can anything be filled in this way?
No. A missing method or object can be rebuilt, but unknown syntax raises an error before execution even starts: no code can catch that. Likewise, a feature requiring hardware access cannot be imitated in JavaScript.
Do I still need them today?
Less and less for a general audience, since browsers update themselves. The question remains for frozen environments, such as browsers embedded in applications or older hardware. Start from your site's analytics rather than a general impression.