Panda CSS 2.0 reemplaza su compilador basado en TypeScript por un motor escrito en Rust sobre Oxc: mantienes la misma API css(), pero la migración es manual. La versión 2.0.0 salió el 29 de septiembre de 2026 y hoy npm sirve la 2.1.2. No hay codemod, y necesitas Node 22 y un proyecto ESM antes de empezar.
¿Qué es Panda CSS y qué tiene que ver con Chakra UI?
Panda CSS es un framework de CSS-in-JS zero-runtime y con tipado estricto, pensado para construir sistemas de diseño. Lo desarrolla el equipo de Chakra UI, con Segun Adebayo a la cabeza; el repositorio vive en chakra-ui/panda, tiene 6.2k estrellas en GitHub y usa licencia MIT. Escribes estilos como objetos tipados con css(), recipes, patterns y props de estilo en JSX. En tiempo de build, Panda los extrae y genera CSS atómico, así que el navegador recibe una hoja de estilos normal y no un runtime de estilos.
Los tokens, las condiciones y los recipes viven en panda.config.ts, y a partir de esa configuración Panda genera una carpeta styled-system con helpers tipados. Si vienes de Chakra UI, la documentación oficial incluye una guía de migración específica, junto con guías desde Tailwind CSS, StyleX, Emotion, Styled Components y vanilla-extract.
¿Qué cambia en Panda CSS 2.0?
Cambia el motor; la forma de escribir estilos no.
En la v1, la extracción pasaba por ts-morph, un envoltorio del compilador completo de TypeScript, y un intérprete de JavaScript evaluaba los valores constantes. En la v2, Oxc analiza cada archivo una sola vez, y ese único parseo se comparte entre imports, llamadas a css(), JSX y resolución de identificadores. Los archivos que nunca importan Panda, incluida la mayor parte de node_modules, se saltan por completo. El CSS se emite de forma nativa en Rust en lugar de pasar por PostCSS.
El motor se distribuye de dos maneras:
| Binding | Paquete | Dónde corre |
|---|---|---|
| Nativo (NAPI) | @pandacss/compiler |
CLI, Vite, PostCSS |
| WebAssembly | @pandacss/compiler-wasm (~490 KB gzip) |
Navegador, playground |
Ambos envuelven los mismos crates de Rust, así que un build en Node y uno en el navegador producen exactamente el mismo CSS.
¿Cuánto más rápido es Panda CSS 2.0?
Estas cifras son benchmarks del propio equipo de Chakra, medidos sobre sus fixtures, que llegan hasta un proyecto sintético de mil archivos:
| Medición | v1 | v2 |
|---|---|---|
| Extracción en frío | — | 15–37× más rápida |
| Parseo en frío, 100 archivos | 187 ms | 7,5 ms |
| Re-parseo en modo watch, por archivo | ~650 µs | menos de 2 µs |
| Paso de parseo, proyecto Next.js | 762 ms | 31 ms |
staticCss, config de ~29.000 reglas |
25,7 s | ~0,3 s |
| Instanciaciones de tipos generados | ~2.600 | ~20 |
El equipo también reporta entre un 21 y un 25 por ciento menos de memoria en tsc, entre un 40 y un 60 por ciento menos de tiempo de type-check, y css() y recipes con memoización, hasta unas 4 veces más rápidos para los estilos que se resuelven en runtime.
¿Qué resuelve el nuevo motor que la v1 no podía?
La v2 sigue los imports. En la v1, un valor de estilo importado desde otro archivo no producía CSS. La v2 lee imports con nombre, re-exports, barrels con export * y alias de rutas de tsconfig, y genera la regla. También resuelve en build miembros de objetos, aritmética en template literals y las dos ramas de un ternario. Si agregaste entradas en staticCss solo porque la v1 no veía un import, ya puedes quitarlas.
Hay dos formas de import que todavía no se siguen: los imports por defecto y los de namespace (import * as theme). Usa imports con nombre.
¿Cómo migrar a Panda CSS 2.0?
Tu panda.config.ts se mantiene, y los binarios panda y pandacss conservan sus nombres. El resto es una lista de cambios que conviene hacer en este orden. Los detalles siguen la guía oficial Upgrading to v2 tal como estaba al 8 de octubre de 2026.
1. Pasa a Node 22 y ESM
La v2 es solo ESM y no tiene build de CommonJS. Define "type": "module" en package.json (o usa .mjs) y convierte cualquier require():
// Antes
const { defineConfig } = require('@pandacss/dev')
// Después
import { defineConfig } from '@pandacss/dev'
Deja postcss.config.cjs como está: sigue en CommonJS a propósito, porque Next.js todavía espera ese archivo en CJS.
2. Actualiza todos los paquetes @pandacss/* juntos
npm install @pandacss/dev@latest
Todos los paquetes @pandacss/* se publican con una sola versión: no mezcles paquetes de la v1 con la v2. Actualiza también a la misma versión las integraciones que uses: @pandacss/postcss, @pandacss/vite, @pandacss/webpack, @pandacss/rollup o @pandacss/bun.
3. Haz un build limpio
panda build --clean # codegen + cssgen en una pasada
panda codegen --clean # o, si solo ejecutas codegen
Solo necesitas --clean una vez, pero no te lo saltes. La v2 no borra los archivos que ya no genera, y la v1 escribía .mjs donde la v2 escribe .js. Vite resuelve index.mjs antes que index.js, así que un archivo sobrante de la v1 puede ganarle al nuevo sin que te des cuenta.
4. Ejecuta panda doctor
panda doctor reemplaza a inspect, validate e info con un único chequeo de salud del proyecto. Agrega --json si lo vas a usar en scripts. Es lo más parecido a una herramienta automática de migración que trae la v2.
5. Corrige la configuración, empezando por los cambios silenciosos
Dos de estos cambios no producen ningún error:
-
Los presets ya no se agregan solos. La v1 inyectaba
@pandacss/preset-baseautomáticamente; la v2 no. Si tu configuración lista solo tus propios presets, pierdes las utilidades y condiciones base. El build sigue funcionando, con advertenciasunknown_condition. Si te faltan componentes comoFlex, es por esto.export default defineConfig({ presets: ['@pandacss/preset-base', '@acme/preset'] }) -
theme.containerSizesahora estheme.containers. La clave antigua se ignora sin advertencia, y todas las condiciones de contenedor@name/sizedejan de funcionar.
El resto de los cambios:
- Los hooks se movieron a
plugins. Cada hook vive ahora en un plugin con nombre, con unfiltery unhandler.cssgen:donepasó a ser de solo lectura: puedes leer el CSS, pero no reescribirlo. Si lo usabas para quitar tokens o keyframes sin uso, cámbialo poroptimize.removeUnusedTokensyoptimize.removeUnusedKeyframes. createStyleContextse dividió en dos:createSlotRecipeContextpara slot recipes (sva) ycreateRecipeContextpara config recipes (cva).- Se eliminó la sintaxis de template literal. Quita la opción
syntaxy reescribecss`color: red;`comocss({ color: 'red' }). definePartsya no existe. Escribe tú el selector[data-part="…"]o usadefineSlotRecipe.- Se eliminaron nueve opciones de configuración:
studio,eject,emitTokensOnly,gitignore,clean,watch,poll,lightningcssybrowserslist. - Cambiaron los imports de tipos.
@pandacss/devahora exporta soloConfig,PresetyUserConfig; el resto viene de@pandacss/types. - Ya no necesitas
@pandacss/plugin-vueni@pandacss/plugin-svelte. El compilador lee archivos.vue,.sveltey.astrodirectamente.
¿Panda CSS 2.0 rompe tu CI?
Puede romperlo, pero por tus scripts de package.json y no por tus estilos. Revisa los scripts con el mismo cuidado que la configuración:
| v1 | v2 |
|---|---|
panda codegen --silent |
panda codegen --log-level silent |
panda cssgen "src/**/*.tsx" |
panda cssgen --include "src/**/*.tsx" |
--cpu-prof |
--profile (escribe trace.json y timings.json, no .cpuprofile) |
panda inspect / validate / info |
panda doctor |
panda mcp |
npx -y @pandacss/mcp |
panda ship |
panda lib |
--poll |
eliminado |
El cambio de los globs posicionales es el más peligroso. En cssgen, analyze y debug, un glob sobrante no falla: Panda simplemente lo ignora y escanea la lista include de tu configuración. El build termina bien, pero escanea archivos distintos de los que esperabas.
Además de los scripts, tu imagen de CI necesita Node 22 o superior.
¿Qué cambia en el CSS generado?
El CSS se mantiene igual que en la v1, salvo una lista corta de cambios deliberados. Conócelos antes de comparar la salida:
- Los breakpoints usan sintaxis de rango,
@media (width >= 48rem), en lugar demin-width. - Los overrides de borde se ordenan por propiedad, no por orden en el código. Un
borderWidthque aplica a todos los lados ahora siempre le gana a unborderInlineEndde un solo lado. Cuando un override tiene que ganar, usa la propiedad larga:borderInlineEndWidth: '0'. - Desaparece el reset universal de variables. Las 34 variables que la v1 ponía en cada elemento ahora se registran con
@propertyy solo se emiten cuando se usan. Esto requiere Chrome 85+, Safari 16.4+ o Firefox 128+. Activaoptimize.propertyFallback: truesi das soporte a navegadores más antiguos. sizes.prosees más angosto en@pandacss/preset-panda: 60ch en lugar de 65ch.scrollbarWidthacepta palabras clave (auto | thin | none), no tokens de tamaño.
Si migras de forma gradual, ojo con las cascade layers. Panda emite su CSS dentro de @layer, y según la especificación de CSS cualquier regla sin capa le gana a todas las reglas con capa. Tus estilos heredados van a ganarle a los componentes ya convertidos, a menos que quites el envoltorio de capa con postcss-cascade-layers o mantengas una frontera clara por ruta o por directorio.
¿Qué vale la pena activar después de migrar?
-
El plugin de ESLint. Valida con el mismo motor de extracción que usa tu build, y también corre bajo oxlint:
// eslint.config.jsimport panda from '@pandacss/eslint-plugin'export default [panda.configs.recommended]Incluye reglas como
no-invalid-token-paths,prefer-token,no-shorthand-longhand-mix,no-deprecatedy unconsistent-property-stylecon autofix. -
viewTransition()permite estilizar la View Transitions API desde tu styled system. -
firstThatWorks()emite un valor moderno con su fallback, por ejemplofirstThatWorks('100dvh', '100vh'). -
keyframes()ypositionTry()definen animaciones y fallbacks de anchor positioning junto al componente que los usa, con tree-shaking según lo que el build realmente referencia. -
panda libydesignSystemte permiten publicar un sistema de diseño como paquete npm y consumirlo sin volver a extraerlo en la app. -
transform: trueen los plugins de Vite, webpack, Rollup o Bun reescribe las llamadas estáticas acss()como strings de clases, de modo que el runtime de estilos desaparece del bundle.
¿Panda CSS o Tailwind?
Ambos generan CSS atómico en tiempo de build; la diferencia está en dónde escribes los estilos. Tailwind usa clases utilitarias en el markup. Panda usa objetos de estilo y props tipados que se validan contra tus tokens, y con la v2 el plugin de ESLint hace cumplir esos tokens también al momento de hacer lint. Si quieres evaluar el cambio, la documentación de Panda incluye una guía de migración desde Tailwind CSS.
¿Y tú? ¿Qué cambio de la v2 te preocupa más al migrar tu proyecto?
- Tailwind CSS
- Panda CSS
- CSS-in-JS con runtime (Emotion, Styled Components)
- Prefiero otra opción (cuéntanos cuál)
Comenta abajo o, si este artículo te llegó por correo, responde directamente al email: tu respuesta se publica aquí.
Relacionado: Feature Friday: Vite 6.0 - La Revolución del Build Tools que Redefine la Velocidad