Ir al contenido
Diseño

Versionar un design system: qué cambios rompen la compatibilidad

El SemVer solo protege a quien usa el sistema si la API pública está escrita. Restringir el tipo de una prop es una major, y a menudo quitar una variable CSS.

4 de noviembre de 2026 · 9 min de lectura

A row of release marks across the top, small grey dots and squares and one large white tile; below, five lanes run right from five tiles on the left, and at the column of the large tile every lane is cut: two cross the gap on small white squares and run on in white, three end at grey rings

Versionar un design system es numerar cada release de una librería de componentes compartida para que quien la usa sepa, solo con el número, si actualizar va a cambiar su producto sin pedirle permiso. La regla detrás del número es el Semantic Versioning: una major para todo lo que rompe a quien usa la librería, una minor para lo que se añade, un patch para las correcciones. Lo difícil es lo primero. En un design system, un cambio incompatible va mucho más allá de una prop renombrada.

La pregunta se vuelve concreta el día en que un segundo producto depende del sistema. Aquí tienes qué incluye la API pública de un design system, qué cambios la rompen y cuáles no, dónde encajan los cambios visuales y cómo se publica un cambio incompatible sin dejar tirados a los equipos que siguen en la versión anterior.

La versión en 30 segundos

Un cambio es incompatible cuando alguien actualiza sin tocar su propio código y obtiene otro resultado: un error de build, un error de tipos, un layout que se ha movido, una auditoría de accesibilidad que falla, un selector de test que ya no encuentra nada. Quitar un componente, quitar una prop o restringir su tipo siempre es una major. Mover las props propagadas a otro elemento, cambiar el display del contenedor de los hijos, dejar de leer una custom property CSS que los consumidores fijan o añadir un landmark main suele ser una major. Añadir un componente, añadir una prop opcional, ampliar un tipo y marcar algo como obsoleto son minor. Un cambio incompatible sale después de al menos una minor que marca como obsoleto el camino antiguo, con una guía de migración y, cuando el trabajo es mecánico, un codemod.

¿Por qué pesa tanto el número de versión?

Porque los gestores de paquetes actúan sobre él sin que nadie lo revise. Con npm install, npm guarda la dependencia con el prefijo caret, así que la versión 1.2.3 se escribe ^1.2.3 (configuración de npm, save-prefix). Un rango caret acepta cualquier minor y patch hasta la siguiente major, sin incluirla: ^1.2.3 cubre todo desde 1.2.3 hasta antes de 2.0.0 (node-semver). Un cambio incompatible publicado como 1.8.0 llega a todos los consumidores en su siguiente instalación limpia, y nadie ha decidido aceptarlo.

La especificación Semantic Versioning 2.0.0 pide una cosa antes que nada: quien la adopta tiene que declarar una API pública, en el código o en la documentación, de forma precisa y completa. Muchos design systems se saltan ese paso. Versionan el paquete y dejan el contrato implícito, así que cualquier comportamiento observable acaba formando parte del contrato igualmente. Hyrum Wright, ingeniero de Google, lo formuló como ley: con suficientes usuarios, alguien dependerá de cada comportamiento observable del sistema (la ley de Hyrum).

¿Qué es la API pública de un design system?

Bastante más que la tabla de props. Quien usa el sistema puede depender de cualquiera de estas siete partes, y cada una necesita una respuesta escrita a la pregunta «¿podemos cambiar esto en una minor?».

  1. Nombres de componentes y props. La ruta de import, el nombre exportado, cada prop y los valores que acepta.
  2. Tipos de las props. En TypeScript el tipo es el contrato. Una unión de tres strings promete que nunca hará falta una cuarta.
  3. Estructura renderizada. Cuál es el elemento raíz, cuál recibe las props propagadas, cómo se colocan los hijos.
  4. Puntos de estilo. Clases, custom properties CSS y atributos data sobre los que un consumidor puede actuar.
  5. Tokens. Primero los nombres, después los valores. Un token renombrado rompe cada hoja de estilos que lo cita.
  6. Semántica de accesibilidad. Roles, landmarks, etiquetas y gestión del foco, que las auditorías de página leen.
  7. Valores visuales. Color, tipografía y espaciado, sobre los que otros equipos montan sus layouts.

Escribir esta lista es el paso que pide el SemVer. Nuestras reglas de API de componentes cubren las tres primeras partes. Las otras cuatro no suelen estar escritas en ningún sitio hasta que algo se rompe.

¿Qué cambios rompen a quien usa el sistema?

El equipo de Primer, el design system de GitHub, publica la tabla más detallada que conocemos: cada tipo de cambio con su salto de versión (guía de versionado de Primer React). Las filas de abajo la siguen, con lo que el consumidor ve de verdad después de actualizar.

CambioSaltoQué ve el consumidor
Se elimina un componente o una propMajorError de build o de tipos al actualizar
Se restringe el tipo de una prop (de cualquier string a tres strings permitidos)MajorErrores de tipos en valores que antes funcionaban
Una dependencia pasa a una nueva majorMajorConflictos de peer o dos copias del mismo paquete
Las props propagadas pasan a otro elementoPotencialmente majorHandlers y props de layout en el nodo equivocado
El contenedor de los hijos cambia de display, de block a flexPotencialmente majorLos espacios desaparecen, los hijos se recolocan
Un componente deja de leer una custom property que los consumidores fijanPotencialmente majorLas personalizaciones dejan de funcionar, sin errores
Un componente añade o quita un landmark main o contentinfoMajorLandmark duplicado o ausente en las auditorías de axe
Se renombra o se quita un atributo data-componentMajorLos tests y los selectores de analítica dejan de encontrar el elemento

Dos filas merecen una mirada más atenta. El cambio de display es el propio ejemplo de Primer: un botón con la etiqueta «Save» seguida de un span «changes» pasa de block a flex, el espacio entre las dos palabras desaparece y el botón muestra «Savechanges». Ningún control de tipos lo detecta. La fila de las custom properties depende de la intención. Si un consumidor fija --example-component-gap y el componente empieza a leer --gap, después de actualizar la personalización ya no hace nada. Primer considera privadas las custom properties de componente salvo que estén documentadas como públicas, que es justo la declaración que pide el SemVer.

¿Qué cambios no rompen nada?

Una minor añade sin quitar. Añadir un componente, añadir una prop opcional y ampliar un tipo (una prop numérica que ahora también acepta un string) son minor en la tabla de Primer, porque todo valor que funcionaba antes sigue funcionando. Marcar como obsoleto un componente o una prop también es una minor: el SemVer exige una minor cuando una parte de la API pública se marca como obsoleta, y la eliminación espera a la siguiente major.

Un patch corrige un comportamiento que contradice la documentación. La trampa es el bug sobre el que los consumidores ya han construido. Si un desplegable siempre se ha cerrado al hacer scroll y tres productos cuentan con ello, la corrección es un cambio de comportamiento para esos tres. Esos los publicamos como minor, con una línea en el changelog que describe el comportamiento antiguo, para que nadie se entere por una incidencia de soporte.

¿Los cambios visuales son cambios incompatibles?

A veces, y es justo donde casi todas las políticas de versionado se callan. En 2018 Nathan Curtis, de EightShapes, defendió que el color, la tipografía y el espaciado necesitan criterios propios para decidir qué rompe, porque quien adopta el sistema monta sus layouts encima. Pocos equipos, señalaba, documentan esos criterios (Visual Breaking Change in Design Systems). Su ejemplo de cambio seguro: oscurecer el fondo del botón principal para subir su contraste.

La prueba que aplicamos es dimensional. Un cambio que deja cada caja del mismo tamaño es una minor: un tono nuevo dentro de la misma franja de contraste, una sombra nueva, un radio retocado. Un cambio que altera las medidas sale como major o detrás de un flag que se activa a mano: un interlineado que suma 2 px a cada fila de una tabla, un token de espaciado que lleva una rejilla de tarjetas de cuatro columnas a tres, una fuente más ancha que manda la etiqueta de un botón a dos líneas. Los consumidores los ven en capturas, nunca en el build, así que los tests de regresión visual en su lado son la única alarma fiable.

¿Cómo se publica un cambio incompatible sin dejar tirado a nadie?

En cinco pasos, cada uno tomado de un sistema que publica su proceso.

  1. Primero, márcalo como obsoleto en una minor. Las FAQ del SemVer piden al menos una minor con el aviso de obsolescencia antes de la major que elimina. Márcalo en los tipos, muestra un aviso en los builds de desarrollo y pon la alternativa en la documentación.
  2. Anuncia el plazo. El design system de Atlassian se compromete a no eliminar ninguna función en disponibilidad general sin un periodo de obsolescencia anunciado con claridad, y a hacer cambios incompatibles solo en las major, que deben ser poco frecuentes (fases de release de Atlassian).
  3. Prepara un codemod para la parte mecánica. La actualización de MUI a la v6 reescribe las props antiguas de Grid en la nueva forma size y offset con un solo comando, npx @mui/codemod@latest v6.0.0/grid-v2-props (guía de migración de MUI v6). Shopify acompaña cada major de Polaris con un migrator por el mismo motivo (guía de Polaris de la v11 a la v12).
  4. Escribe la guía de migración para el resto. Un codemod resuelve los renombres. Un layout que se recoloca no lo puede resolver, así que la guía lista cada cambio visual con un antes y un después.
  5. Convierte el salto de versión en una decisión en cada cambio. Primer exige un archivo changeset en cada pull request que toca la API pública o el comportamiento en runtime, declarando patch, minor o major (Changesets). El salto se discute en la revisión, junto al diff, en lugar de adivinarlo el día del release.

¿Una versión para toda la librería o una por componente?

Curtis describe los dos modelos (Versioning Design Systems). Con un solo paquete, un cambio incompatible en cualquier componente lleva toda la librería a la siguiente major, también para quien nunca importa ese componente. Con un paquete por componente, como hace Atlassian, un botón puede estar en una major y un modal en otra, y cada uno actualiza solo lo que ha cambiado. El coste pasa a las dependencias: un componente que envuelve a otro tiene que volver a publicarse cada vez que cambia su dependencia, y un consumidor puede acabar con dos versiones de la misma primitiva en un solo bundle.

Para un sistema con pocos consumidores, un paquete único es más fácil de seguir, y una major de toda la librería es más un problema de calendario que técnico. Las versiones por componente compensan cuando los consumidores actualizan a ritmos muy distintos. Las reglas de salto de versión valen en los dos modelos.

Conceptos cercanos

El versionado es una parte de la gestión de un sistema compartido. Gobernar un design system en diez proyectos explica quién decide qué sale. El component drift cuenta qué pasa cuando los consumidores dejan de actualizar y copian los componentes. Una documentación que se lee es el sitio donde se escribe la API pública. Y la comparación entre design tokens y variables CSS explica por qué un token renombrado llega más lejos que una prop renombrada.

Preguntas frecuentes

Servicios relacionados

Artículos relacionados

Studio

Empieza un proyecto.

Escribimos sobre lo que construimos. Cuéntanos qué quieres construir tú.