¿Alguien sigue usando polyfills en 2026?
¿Polyfills en 2026? Audita core-js, Browserslist y Babel para quitar peso muerto, conservar Temporal y abandonar polyfill.io.
Sí — pero casi ninguno de los que heredó tu bundler. La configuración de polyfills en bloque que tenía sentido en 2019 — enviar @babel/preset-env con useBuiltIns: 'entry' contra un target amplio de Browserslist — ahora manda peso muerto a la gran mayoría de los usuarios para dar soporte a una cuota de navegadores que se redondea a cero. Un polyfill sigue siendo la herramienta adecuada para una lista corta y concreta de funcionalidades genuinamente no soportadas en 2026 — y una carga para todo lo demás.
Este artículo resuelve una sola decisión: si los polyfills en tu pipeline de build actual todavía justifican los bytes que ocupan. Identifica qué APIs son peso muerto, cuáles siguen necesitando legítimamente un polyfill, qué cambió el incidente de seguridad de polyfill.io en la forma de cargarlos, y los comandos exactos para auditar lo que realmente estás enviando.
Conclusiones clave
- Para una aplicación React, Vue, Svelte o Next.js que apunta a navegadores evergreen en 2026, el número correcto de polyfills para la mayoría de los equipos es cercano a cero — con excepciones concretas para Decorators, Temporal durante su transición entre navegadores, y entornos con navegadores corporativos bloqueados.
Array.flat,Object.entries,Promise.allSettled,structuredClone, optional chaining, nullish coalescing yfetchtienen soporte amplio en 2026; incluir polyfills para ellos envía bytes que casi ningún usuario real necesita.- El patrón de polyfill remoto (cargar un script desde polyfill.io) está muerto tras el incidente de seguridad en la cadena de suministro de 2024; Cloudflare y Fastly levantaron mirrors, pero el patrón en sí ya no es defendible.
- Ejecuta
npx browserslistpara ver exactamente qué navegadores apunta tu configuración, y luego usasource-map-explorerpara encontrar cuánto peso decore-jsestás enviando. - La clasificación Enhancement / Additive / Critical de web.dev es el marco más sólido para decidir si la ausencia de una funcionalidad justifica un polyfill.
La línea base de soporte nativo en 2026: lo que ya no necesitas polyfillizar
La mayoría de las funcionalidades de JavaScript que las configuraciones de build siguen polyfillizando de forma rutinaria ya tienen soporte en todos los navegadores evergreen, lo que significa que incluir polyfills para ellas envía bytes que casi ningún usuario real necesita. Las funcionalidades que anclaron los tutoriales de polyfills durante una década — Math.trunc, Array.prototype.flat, optional chaining — ahora tienen soporte amplio y son exactamente el peso muerto que una auditoría en 2026 debería eliminar.
El ejemplo didáctico por excelencia, el polyfill de Math.trunc de javascript.info, es la ilustración más clara. Math.trunc tiene soporte universal en navegadores desde 2015 — según los datos de compatibilidad de MDN, llegó en Chrome 38, Firefox 25 y Safari 8. Escribir o incluir un polyfill de Math.trunc en 2026 es enviar una cláusula de guarda para un navegador que nadie usa.
Lo mismo ocurre en toda la superficie de API que las configuraciones obsoletas siguen apuntando. Los porcentajes de soporte que aparecen a continuación provienen de los datos de uso global de caniuse.com (StatCounter, mayo de 2026); “soporte global” hace referencia a la cuota de navegadores ponderada de caniuse en todas las versiones rastreadas.
| Funcionalidad | Soporte global (caniuse, 2026) | ¿Sigue valiendo la pena polyfillizar? |
|---|---|---|
Array.prototype.flat | 94,11% | No |
Object.entries | 95,06% | No |
Promise.allSettled | 94,04% | No |
structuredClone | 93,84% | No |
Optional chaining (?.) | 93,99% | No (es sintaxis — transpila, no polyfillices) |
Nullish coalescing (??) | 93,99% | No (es sintaxis — transpila, no polyfillices) |
fetch | 96,3% | No |
Temporal | 65,16% | Sí — transitoriamente |
| Decorators | 0% nativo | Sí |
Array.flat, Object.entries, Promise.allSettled, structuredClone, optional chaining, nullish coalescing y fetch se sitúan alrededor del 94–96% de soporte global — y si tu configuración de Babel sigue polyfillizando estos, estás enviando bytes que casi ningún usuario necesita.
Sintaxis vs. funciones: Optional chaining y nullish coalescing son sintaxis, no funciones ausentes, por lo que las gestiona un transpilador, no un polyfill. Como señala javascript.info: usa un transpilador para sintaxis u operadores modernos, y polyfills para funciones ausentes. La distinción importa al auditar — un “polyfill” de
??en tu configuración es una señal de que la configuración está confundiendo ambos conceptos.
¿Qué polyfills siguen justificando su lugar en 2026?
Discover how at OpenReplay.com.
Los polyfills siguen siendo la herramienta correcta para un conjunto pequeño y concreto de casos: funcionalidades sin soporte nativo en ningún navegador, funcionalidades en transición entre navegadores, y entornos con navegadores bloqueados donde la suposición evergreen no aplica. Estas son las excepciones que justifican mantener un mecanismo de polyfills en tu pipeline.
Decorators. La propuesta de decorators de TC39 está en Stage 3 sin ninguna implementación nativa en navegadores. Si usas decorators — directamente, o a través de un framework como Angular o una librería que depende de ellos — estás dependiendo de un transpilador más, en algunos casos, helpers de tiempo de ejecución. Aquí no existe la opción de “esperar al soporte nativo”; la funcionalidad aún no está disponible en los navegadores.
Temporal, durante su transición entre navegadores. Temporal es una propuesta TC39 finalizada — aparece en la lista de propuestas finalizadas de TC39 — y ha comenzado a llegar de forma nativa. Según los datos de compatibilidad de Temporal en MDN, está disponible en Firefox 139+, Chrome 144+, Edge 144+ y Node.js 26+, mientras que Safari aún carece de soporte habilitado. Ese despliegue desigual convierte un polyfill de Temporal en una necesidad transitoria en lugar de permanente. El repositorio proposal-temporal de TC39 lista @js-temporal/polyfill como una opción en versión alfa junto a otras alternativas — no es la única opción canónica.
Entornos corporativos y navegadores bloqueados. Los sistemas financieros regulados, las intranets gubernamentales y los dispositivos kiosk o POS a veces fijan una versión de navegador durante años. Si tu base de usuarios real incluye navegadores que no pueden actualizarse, tu target de Browserslist es más amplio que el predeterminado evergreen y algunos polyfills son fundamentales. La palabra clave es real — este caso se alega con mucha más frecuencia de lo que se mide. Valídalo contra tus analíticas antes de mantener polyfills por este motivo.
Funcionalidades CSS de disponibilidad limitada con polyfills en JavaScript. Algunas capacidades de CSS, como container queries en versiones antiguas de Safari, se polyfillizaron con JavaScript durante su despliegue. Como señala web.dev, el polyfill de container queries usa ResizeObserver y MutationObserver para imitar el comportamiento nativo — y su README lo marca como sin mantenimiento activo. Estos polyfills tienen advertencias de comportamiento que se tratan más adelante.
El consenso general — “usa polyfills específicos, basa las decisiones en datos” — no está equivocado, pero subestima cuánto ha cambiado la situación: para la mayoría de las aplicaciones en 2026, “los polyfills siguen teniendo un papel importante” ya no es cierto. El papel es ahora estrecho y concreto.
El incidente de polyfill.io acabó con el patrón de polyfill remoto
El patrón de polyfill remoto — cargar un <script> desde una CDN de terceros que devuelve polyfills adaptados al navegador — ya no es una arquitectura defendible tras el ataque a la cadena de suministro de polyfill.io en 2024. El incidente obligó a los equipos a auditar lo que cargaban de terceros, y la mayoría descubrió que no necesitaba casi nada de ello.
La cronología:
- Principios de 2024 — cambio de propietario. El dominio polyfill.io cambió de manos. La publicación de la comunidad de Fastly documenta el cambio y la respuesta de Fastly para los usuarios afectados.
- 25 de junio de 2024 — informe de malware. La empresa de seguridad Sansec informó de que el servicio polyfill.io estaba inyectando malware en el script que servía a los usuarios finales.
- Junio de 2024 — mirrors y respuestas de mitigación. Cloudflare anunció la sustitución automática de los enlaces a polyfill.io por su propio mirror, y Fastly ofreció un endpoint alternativo.
Los mirrors mantienen el funcionamiento de los sitios existentes, pero no rehabilitan el patrón. Un modo de fallo de producción estándar que esto puso al descubierto: los equipos tenían una etiqueta <script> apuntando a cdn.polyfill.io que cargaba paquetes de polyfills que habían dejado de necesitar años atrás, ejecutando JavaScript de terceros en cada carga de página para dar soporte a navegadores que ya se habían actualizado. No trates el mirror de Cloudflare o Fastly como un reemplazo “seguro” — trata el incidente como la señal para eliminar la etiqueta <script> por completo y mover los polyfills genuinamente necesarios a tu propio bundle, donde tú los controlas y revisas.
Cómo auditar lo que tu bundler está enviando realmente
Auditar tu footprint de polyfills es una secuencia de cuatro pasos: leer tu target real de Browserslist, inspeccionar el bundle en busca del peso de core-js, corregir la configuración de Babel y validar contra datos reales de usuarios. Nada de esto requiere suposiciones — cada paso es un comando o un diff de configuración que puedes ejecutar hoy mismo.
Paso 1: Consulta tu lista de targets real
Las consultas de Browserslist determinan qué navegadores soporta tu configuración, y la única forma fiable de saber a qué se resuelve la tuya es preguntarle directamente:
npx browserslist
Esto imprime la lista concreta de versiones de navegadores que apunta tu configuración actual. Los valores predeterminados de Browserslist (> 0.5%, last 2 versions, Firefox ESR, not dead) ya excluyen IE11 mediante not dead. El riesgo real es una consulta personalizada heredada — un > 0.2% suelto o un umbral de versión explícito de hace años — que silenciosamente incluye targets obsoletos. Ejecuta el comando; si el resultado incluye navegadores que ningún usuario real utiliza, ahí está tu peso muerto.
Paso 2: Encuentra el peso de core-js en tu bundle
core-js es la librería de polyfills de la que @babel/preset-env inyecta, y puede representar una fracción sustancial de un bundle que no la necesita. Inspecciona un build de producción:
npx source-map-explorer dist/assets/*.js
source-map-explorer renderiza un treemap de lo que contiene cada bundle a partir de sus source maps. Busca módulos de core-js — es.array.flat, es.object.entries, es.promise.all-settled. Cada uno de ellos corresponde a una funcionalidad de la tabla de peso muerto anterior. (Para proyectos webpack, webpack-bundle-analyzer ofrece la misma vista.)
Paso 3: Corrige la configuración de Babel
La configuración canónica que la mayoría de los equipos heredó está incompleta. Un patrón habitual tiene este aspecto:
{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "usage",
"corejs": 3
}]
]
}
Esta configuración tiene dos problemas. Primero, no hay campo targets, por lo que la configuración recurre a tu archivo Browserslist — que puede ser la consulta personalizada obsoleta del Paso 1. Segundo, corejs: 3 no está fijado a una versión menor; según la documentación de core-js, la versión debería especificar un minor para que preset-env inyecte polyfills que coincidan con la versión instalada. Una versión apropiada para 2026:
{
"presets": [
["@babel/preset-env", {
"targets": "> 1%, last 2 versions, not dead",
"useBuiltIns": "usage",
"corejs": "3.40"
}]
]
}
Fija corejs a la versión minor que realmente tienes instalada en lugar de copiar cualquier número — preset-env la usa para decidir qué polyfills existen para inyectar.
El valor de useBuiltIns es la configuración más determinante. Según la documentación de @babel/preset-env:
'entry'reemplaza un únicoimport 'core-js'con el conjunto completo de polyfills que requieren tustargets— amplio, y el origen de la mayor parte del bloat heredado.'usage'añade polyfills solo para las funcionalidades que tu código referencia realmente, por archivo. Esto es casi siempre lo que quieres: limita la inyección de polyfills al uso real en lugar de toda tu matriz de targets.
Paso 4: Valida contra datos reales de usuarios
Una configuración es una hipótesis sobre tus usuarios; los datos de RUM la confirman o refutan. web.dev recomienda medir el soporte real de funcionalidades antes de decidir polyfillizar, y señala RUM Insights como fuente de datos amplia. El patrón es el siguiente: las funcionalidades en el conjunto Baseline Widely Available tienen soporte en el 98% o más de los usuarios. Si tus analíticas muestran una funcionalidad cerca de ese umbral, el polyfill para ella está sirviendo a una fracción que se redondea a ruido estadístico.
¿Cuándo deberías polyfillizar? El marco Enhancement, Additive, Critical
Cuando una funcionalidad genuinamente no tiene soporte en tu base real de usuarios, la clasificación Enhancement / Additive / Critical de web.dev es la heurística más útil para decidir si polyfillizar: si la ausencia de una funcionalidad es invisible para los usuarios, no polyfillices; si degrada de forma elegante, inclínate por no polyfillizar; solo cuando la ausencia rompe la experiencia justifica un polyfill su coste en rendimiento.
Los tres niveles, tal como los define web.dev:
- Enhancement — la funcionalidad mejora la experiencia, pero su ausencia no produce ningún cambio visual ni pérdida de funcionalidad. Las pistas de rendimiento como
fetchpriorityson el ejemplo. Los usuarios en navegadores sin soporte no lo notarán. No polyfillices. - Additive — la funcionalidad puede afectar al aspecto o funcionamiento de una página, pero no de una forma que genere problemas graves; un usuario solo podría notarlo comparando navegadores. Si existe un polyfill, inclínate por no usarlo, especialmente si ya estás polyfillizando otras cosas. Las funciones de color y subgrid son ejemplos.
- Critical — la ausencia provoca una experiencia rota: errores en tiempo de ejecución, layouts rotos, funcionalidad inutilizable. Aquí un polyfill (o un enfoque completamente diferente) está justificado.
La regla de anclaje de web.dev encaja perfectamente con la tabla de soporte anterior: si una funcionalidad está Widely Available no deberías recurrir a un polyfill — a menos que tengas datos sobre tus usuarios que te indiquen explícitamente lo contrario.
Por qué los bugs de polyfills se ocultan — y cómo los detecta la reproducción de sesión
Los bugs de polyfills pertenecen a una clase que los conjuntos de pruebas estándar pasan por alto por completo: solo se manifiestan en la fracción de navegadores que activó el polyfill, que nunca es el navegador evergreen contra el que ejecuta tu CI. La reproducción de sesión es una de las pocas técnicas de observabilidad que captura el estado real del DOM de esos usuarios, porque registra la secuencia real de interacción y mutación desde el navegador que ejecutó la ruta del polyfill.
La reproducción de sesión detecta tres patrones concretos de divergencia entre las rutas de código polyfillizadas y las nativas:
- Timing de layout shift en el polyfill de container queries. Como señala web.dev, el polyfill de container queries gestiona el layout desde callbacks de
ResizeObserver, que se disparan justo antes de que el navegador pinte un nuevo frame — aumentando el retraso de presentación y afectando al Interaction to Next Paint. El timing de repintado retrasado puede producir layout shifts que solo son observables en los navegadores que necesitaban el polyfill. - Divergencia de zonas horarias en Temporal. Durante la transición de Temporal entre navegadores, los equipos pueden necesitar probar tanto la implementación nativa como la polyfillizada de
Temporalpara garantizar un comportamiento consistente entre navegadores. Tu conjunto de pruebas puede ejecutarse contra una sola ruta de implementación, mientras que los usuarios reales encuentran otra; las reproducciones de navegadores donde coexisten implementaciones nativas y polyfillizadas pueden ayudar a detectar esas diferencias. - Brechas en la gestión del foco. Los polyfills orientados a la accesibilidad pueden introducir problemas sutiles de navegación por teclado y gestión del foco en navegadores sin soporte nativo — el tipo de fallo que web.dev destaca de forma más general. Una reproducción con captura de eventos de teclado muestra al usuario navegando por tabulación a través de un fondo modal, algo que una prueba automatizada exitosa contra el polyfill no revelará.
En cada caso el factor común es el mismo: el bug vive en la fracción de usuarios que tu entorno de desarrollo nunca reproduce. Esa es la razón estructural para enviar menos polyfills — cada ruta de polyfill que eliminas es una ruta de divergencia que ya no tienes que monitorizar.
Acciones concretas para esta semana
Reducir tu footprint de polyfills es una secuencia de ediciones pequeñas y reversibles, cada una validada contra el bundle y tus usuarios. El objetivo es usar código nativo donde puedas, cargar condicionalmente para la cola larga genuina, y eliminar todo lo demás.
- Ejecuta
npx browserslisty elimina cualquier consulta personalizada heredada que apunte a navegadores que ningún usuario real utiliza. Cambiar a un target más ajustado y actual es el cambio de mayor impacto que puedes hacer. - Establece
useBuiltIns: 'usage'y un campotargetsexplícito en tu configuración de@babel/preset-env, y fijacorejsa tu versión minor instalada. - Compara el bundle antes y después con
source-map-explorerpara confirmar que el peso decore-jsrealmente bajó, luego ejecuta tus pruebas para verificar que nada necesario desapareció. - Elimina cualquier etiqueta
<script>decdn.polyfill.iopor completo; mueve los polyfills genuinamente necesarios a tu propio bundle. - Carga condicionalmente las excepciones reales. Para Temporal durante su transición, carga el polyfill solo para los navegadores que lo necesiten en lugar de enviarlo a todos. Para Decorators, confía en la transpilación y los helpers de tiempo de ejecución donde sea necesario. El punto de web.dev de que los polyfills para funcionalidades de disponibilidad limitada deben cargarse condicionalmente aplica directamente aquí.
- Valida con datos de RUM antes y después, para que la auditoría se base en tus usuarios, no en la media global.
Conclusión
La respuesta honesta en 2026 a si alguien sigue usando polyfills es sí — pero la lista defendible es corta y concreta: Decorators, Temporal mientras cruza la brecha entre navegadores, y entornos con navegadores bloqueados que has medido realmente. Todo lo demás que heredó tu configuración son bytes gastados en una cuota de navegadores que se redondea a cero, y el incidente de polyfill.io es el recordatorio de que cargarlos de forma descuidada conlleva riesgos reales. Empieza con npx browserslist hoy mismo; la brecha entre lo que imprime y los navegadores que tus usuarios realmente utilizan es tu presupuesto de polyfills, y para la mayoría de los equipos es mucho menor de lo que la configuración asume.
Preguntas frecuentes
¿Cuál es la diferencia entre un polyfill y un transpilador?
Un transpilador reescribe sintaxis moderna en un equivalente más antiguo en tiempo de compilación, mientras que un polyfill añade una función o implementación de API ausente en tiempo de ejecución. Las funcionalidades de sintaxis como optional chaining y nullish coalescing las gestiona un transpilador porque son operadores del lenguaje, no funciones invocables. Las APIs como Promise.allSettled o structuredClone las gestionan los polyfills porque son métodos ausentes que el código en tiempo de ejecución puede proporcionar. Un 'polyfill' de nullish coalescing en tu configuración es una señal de que ambos conceptos se han confundido.
¿Cuál es la diferencia entre useBuiltIns 'usage' y 'entry' en babel-preset-env?
Con useBuiltIns establecido en 'entry', Babel reemplaza un único import de core-js con el conjunto completo de polyfills que requieren tus targets, que es el origen de la mayor parte del bloat heredado en los bundles. Con 'usage', Babel inyecta polyfills solo para las funcionalidades que tu código referencia realmente, con alcance por archivo. El valor 'usage' es casi siempre preferible porque envía polyfills para el uso real en lugar de toda tu matriz de targets. Ambos requieren una versión de corejs fijada a tu versión minor instalada.
¿Es seguro seguir usando polyfill.io a través del mirror de Cloudflare o Fastly?
Los mirrors de Cloudflare y Fastly mantienen el funcionamiento de los sitios existentes, pero no rehabilitan el patrón de polyfill remoto. Después de que el dominio polyfill.io cambiara de propietario a principios de 2024 y Sansec informara el 25 de junio de 2024 de que el servicio estaba inyectando malware, cargar polyfills adaptados al navegador desde una CDN de terceros se volvió indefendible para los equipos conscientes de la seguridad. Elimina la etiqueta de script de cdn.polyfill.io por completo y mueve los polyfills genuinamente necesarios a tu propio bundle, donde tú los controlas y revisas.
¿Sigo necesitando core-js si mi aplicación apunta solo a navegadores evergreen?
Para la mayoría de las aplicaciones que apuntan a navegadores evergreen en 2026, core-js envía cerca de cero polyfills útiles, porque funcionalidades como Array.flat, Object.entries, Promise.allSettled, structuredClone y fetch ya tienen soporte amplio. Las excepciones concretas son Decorators, que no tiene implementación nativa en ningún navegador, y Temporal durante su despliegue desigual entre navegadores. Ejecuta source-map-explorer contra un build de producción para ver qué módulos de core-js están presentes, luego ajusta tu target de Browserslist y cambia useBuiltIns a 'usage' para eliminar el peso muerto.