Ir al contenido

Cómo hacer migraciones con Claude Code y no morir en el intento

Tres migraciones reales con Claude Code: el toolchain de un monorepo, screaming architecture y el rediseño de este sitio. Lo que antes tomaba semanas, hoy se hace en días.

8 minClaude Code · Migrations · Tooling leer en inglés

Migrar dejó de doler

Migré el diseño completo de este sitio en un par de días. Antes de Claude Code, esa misma migración me la habría comido en dos semanas, y probablemente la habría postergado seis meses por pura flojera.

Llevo años haciendo migraciones. Vue 2 a Vue 3, design systems completos, refactors arquitectónicos que tocaban cientos de archivos. Todas tenían algo en común, dolían. Eran proyectos largos, mecánicos, con riesgo alto y poca recompensa visible. La clase de tarea que sabes que hay que hacer pero que sigues postergando porque suena a infierno.

Ya no.

El dolor histórico de migrar

Migrar de Vue 2 a Vue 3 era un proyecto trimestral. No por las dificultades técnicas reales (la mayoría era reemplazar APIs deprecadas), sino por el volumen. Cientos de componentes, cada uno con sus particularidades, todos había que tocarlos. Sumarle Pinia, Vue Router 4, los plugins de terceros que no soportaban v3 todavía. Y mientras hacías la migración, el resto del equipo seguía mergeando features en la rama principal. Cuando intentabas mergear de vuelta, era un infierno.

Migrar un design system era parecido pero peor. Cambias el sistema de tokens, los componentes base, los nombres de las props. De pronto cada <Button variant="primary" /> que existía en la app necesita revisión, y cuando son cientos de ocurrencias, ningún equipo te firma un Q completo solo para eso.

El patrón siempre era el mismo, alta carga, baja motivación, postergación indefinida.

Por qué las migraciones son el escenario perfecto para un agente

Después de hacer varias con Claude Code, identifiqué tres condiciones dónde son ideales:

  1. Alto volumen de cambios mecánicos. El PR de oxlint en mi trabajo actual tocó más de 700 archivos. La mayoría eran ajustes triviales (orden de imports, patrones equivalentes). Es exactamente el tipo de trabajo que es humanamente tedioso y que un agente lo hace en minutos.
  2. Feedback claro y automatizable. Linter, Typecheck, Tests, pasan o no pasan. El Build compila o no compila. Cada paso es un loop con respuesta binaria, justo el tipo de señal que un agente necesita para iterar sin supervisión continua.
  3. Documentación accesible. La herramienta de destino casi siempre tiene un migration guide. Le pasas el guide al agente, le das el contexto del proyecto, y deja de inventar.

Si tu tarea cumple las tres, deja de procrastinar. Es trabajo para un agente.

Caso 1: el toolchain de un monorepo

El equipo en mi trabajo actual operaba un monorepo con 7 aplicaciones en Cloudflare Workers, alrededor de 1.670 archivos de TypeScript gestionados con pnpm workspaces. El pipeline de calidad usaba Biome para lint y format, y tsc para type-check.

Dos cuellos de botella:

  • Biome y tsc requerían NODE_OPTIONS='--max-old-space-size=8192' para no caer por out of memory durante CI.
  • tsc, single-threaded, se demoraba 25 segundos en chequear los tipos del monorepo completo.

Llevábamos meses mirando lo que el equipo de oxc (oxlint, oxfmt, todo lo que están construyendo en Rust) iba sacando. La pregunta no era si valía la pena migrar, sino cuánto esfuerzo iba a costar.

Migración a oxlint + oxfmt

Los pasos:

  1. Reemplazar Biome por oxlint y oxfmt.
  2. Configurar .oxlintrc.json con 129 reglas activas.
  3. Configurar .oxfmtrc.json equivalente.
  4. Actualizar scripts en package.json.
  5. Ajustar el pipeline en GitHub Actions.
  6. Ajustar la config del editor.

El bulk del trabajo no fue cambiar las herramientas. Fue ajustar el código para cumplir las nuevas reglas (la mayoría sobre orden de imports y patrones equivalentes). Claude Code hacía los cambios, corríamos las validaciones, ajustábamos, repetíamos.

MétricaBiomeoxlint (ene 2026)oxlint (mar 2026)
Tiempo promedio3.70s1.04s0.49s
Archivos analizados1.2271.262~1.670

oxlint procesaba más archivos con más reglas en una fracción del tiempo. Y la herramienta sigue mejorando con cada release.

Migración a tsgo

TypeScript 7 (tsgo) es la reescritura de tsc (TypeScript Compiler) en Go. Microsoft prometía mejoras de 7x a 10x. La migración fue todavía más directa:

  1. Instalar @typescript/native-preview.
  2. Cambiar el script de NODE_OPTIONS='--max-old-space-size=8192' tsc a tsgo.
  3. Ajustar tsconfig.json (sacar baseUrl, agregar ./ como prefijo en paths).
  4. Actualizar la caché en CI (de .tsbuildinfo a .tsgo-cache).
  5. Corregir tipos en los lugares donde tsgo es más estricto que tsc.

El bonus, ya no necesitas la config de memoria. tsgo corre en Go sin las restricciones de Node.

Métricatsctsgo (ene 2026)tsgo (mar 2026)
Tiempo (cold)25.34s5.32s0.76s
Uso CPU~132%~430%~430%
Requiere config de memoriaSí (8 GB)NoNo

33 veces más rápido en typecheck, sin tocar una sola línea de código TypeScript del proyecto.

El número final

FaseAntesMigraciónHoy (abril 2026)
Lint3.70s1.04s0.49s
Typecheck25.34s5.32s0.76s
Total29.04s6.36s1.25s

De 29 segundos a 1.25. 23 veces más rápido. Y lo que terminó de convencer al equipo fueron precisamente esos números. Sin medir antes y después, la migración es solo "Sergio cambió las herramientas". Con los números, es "el feedback de calidad de código es 23X más rápido".

Lección: mide siempre. Es lo que convierte una migración en una historia que el equipo entiende y firma.

Caso 2: screaming architecture en un frontend grande

Antes de la migración del toolchain, había hecho otra: aplicar screaming architecture al frontend del producto principal. Reorganizar el repo desde carpetas técnicas (components/, services/, store/) a módulos por feature (modules/Auth/, modules/Orders/, etc).

El cambio en sí es simple: mover archivos y actualizar imports. Pero cuando son cientos de archivos en cientos de imports, es la definición de "trabajo mecánico que nadie quiere hacer un viernes".

Acá es donde Claude Code se luce. El patrón es uniforme, los cambios son verificables (compila o no), y la única regla nueva es "todo lo de feature X vive en modules/X/". El agente entiende el patrón al primer ejemplo y lo aplica al resto.

Lo único que hice fue definir el contrato (specs). Qué módulos crear, qué se considera shared, cómo manejar los archivos que tocaba más de una feature. Después fue iterar, validar build, validar tests, ajustar.

Lección: los refactors estructurales son ideales cuando el patrón es claro pero el volumen es alto. Define las reglas una vez, deja que el agente las aplique en todas partes.

Caso 3: el rediseño de este sitio

El más reciente y el más cercano a este post. Migrar sergioazocar.com desde el diseño anterior al actual: layout edge-to-edge con BentoGrid, Nuxt UI v4, Tailwind v4, sistema de colores custom (beacon y orbit), tema dark-only, borders translúcidas con color-mix.

La diferencia con los casos anteriores es que el contexto del proyecto era todo mío. Tengo un CLAUDE.md cuidado, con las convenciones del repo, el stack, las reglas de i18n, los patrones de blog posts, los gotchas. Cuando le pido a Claude Code que migre un componente al nuevo sistema de borders, no necesito explicarle qué es border-(muted) ni dónde está definido. Ya lo sabe.

Eso es dogfooding. El proyecto está preparado para que el agente sea útil desde el primer prompt. Y eso paga dividendos rapidísimo, cada turno avanza en lugar de gastarse en re-explicar contexto.

Lección: invertir en un buen CLAUDE.md no es overhead, es la diferencia entre un agente útil y uno que alucina.

El playbook

Después de varias migraciones, esto es lo que hago siempre:

  1. Planifica antes de generar. Una migración mal scopeada es una migración fallida. Define el alcance, los pasos, los archivos. Si no tienes claridad antes de empezar, el agente tampoco la va a tener.
  2. PRs atómicos por fase. En el caso del toolchain, oxlint y tsgo fueron PRs separados. Si algo se rompe, sabes exactamente qué fase lo causó.
  3. Valida en cada paso. Lint, type-check, tests, preview. Claude Code corre los comandos, tú lees el output. Saltarte la validación porque "el cambio anterior pasó" es la receta para acumular 50 errores antes de darte cuenta.
  4. Mantén un CLAUDE.md actualizado. Stack, convenciones, comandos, gotchas del proyecto. Es la diferencia entre un agente que entiende el repo y uno que inventa.
  5. Mide antes y después. Sin números no hay historia que contar, ni argumento para venderle al equipo.
  6. Pair programming, no autopilot. El agente no reemplaza criterio, lo amplifica. Tú decides qué se hace, él lo ejecuta y trae el feedback.

Lo que NO hagas

  • No le pidas todo de una vez. "Migra el repo entero" es la peor instrucción posible. Divide en fases, una a la vez.
  • No te saltes la validación. Aunque el cambio se vea trivial, corre los checks. El error que asumes que no existe es el que termina en producción.
  • No dejes que invente paths o APIs. Si cita una función que no reconoces, verifica que existe antes de aceptar el cambio.
  • No mergees sin entender los cambios. El agente acelera tu trabajo, no reemplaza tu responsabilidad. Si no entiendes lo que se cambió, no estás migrando, estás cruzando los dedos.

Cierre

La barrera de entrada para migrar bajó dramáticamente. Lo que antes era un proyecto trimestral hoy es un proyecto de fin de semana. Lo que antes postergabas seis meses, lo puedes iniciar hoy mismo y terminarlo en un par de días.

Si tienes una migración estancada hace tiempo, abre Claude Code esta semana. Probablemente la termines antes de que termine el sprint.

Y aunque las métricas finales no salgan tan lindas, igual vas a entender más de tu codebase en dos días que en los seis meses que llevabas postergándolo.

Nuevos posts en tu inbox

Escribo sobre desarrollo de software, herramientas que voy probando y cosas que aprendo construyendo. Cuando publico algo nuevo, te llega al email. Sin más.

Sin spam. Cancela cuando quieras.