Qué es trunk based development: guía operativa para SRE
Resumen
Trunk based development es un modelo de ramas en el que todo el equipo integra cambios pequeños en una rama principal al menos una vez al día y la mantiene desplegable. Para funcionar necesita un CI de unos diez minutos, pruebas fiables, revisiones rápidas y flags de funcionalidad o branch by abstraction para el trabajo incompleto. Esta guía explica qué exige el modelo, dónde falla y cómo empezar sin una migración de big-bang.
Son las 3 de la mañana y la rama de release no se puede fusionar. Cuarenta commits, tres semanas de antigüedad, tocando los mismos archivos que main. Ese dolor es el argumento más sólido a favor del trunk based development: ¿qué es trunk based development, exactamente? Es un modelo de ramas en el que todo el equipo integra cambios pequeños en una única rama compartida, llamada trunk o main, al menos una vez al día, y la mantiene lista para desplegarse en todo momento.
Esta guía está pensada para ingenieros de plataforma que ya dominan Git. Explica lo que exige el modelo, de qué te protege y dónde se rompe en silencio.
¿Qué es trunk based development en términos operativos?
Reduce la definición a sus restricciones. Todos los desarrolladores integran en una sola rama. Cualquier otra rama vive horas, no semanas. El trunk compila y pasa las pruebas en cada commit, así que puede salir a producción cuando haga falta.
La página de capacidades de DORA pone cifras: tres ramas activas o menos en el repositorio, fusiones al trunk al menos una vez al día, ningún code freeze y un ciclo de build y pruebas que dura unos minutos. Esas cifras son el punto. El modelo es un presupuesto de bucle de retroalimentación, no una preferencia de estilo de ramas.

Los equipos pequeños a veces hacen commit directo al trunk. Los más grandes usan ramas de vida corta y pull requests para la revisión y las comprobaciones de build, pero nunca para retener trabajo fuera de la integración. La referencia trunkbaseddevelopment.com describe ambos modos y cita a Google, que mantiene unos 35.000 desarrolladores sobre un único trunk dentro de un monorepo.
Por qué las ramas de larga vida fallan en un calendario predecible
Una rama de funcionalidad es un préstamo. El interés es el conflicto de fusión, y se acumula con cada commit que aterriza en main mientras tú estás fuera. Cuanto más vive la rama, mayor es el diff, y cuanto mayor es el diff, menos gente lo lee con atención.
Esto afecta a tu tasa de fallos en cambios. Una fusión de 2.000 líneas se hojea y se aprueba. Una de 60 líneas se lee. Los revisores no son perezosos: racionan la atención. Los lotes pequeños son el único mecanismo que escala la calidad de la revisión.
El segundo coste es invisible hasta el momento de la release. Dos ramas que pasan CI por separado pueden romperse mutuamente al encontrarse. Lo descubres en el momento de la integración, el peor posible, con una fecha límite encima.
Lo que el trunk necesita antes de que puedas confiar en él
Pasar a trunk sin las prácticas de soporte es la forma más segura de que un equipo vuelva a las ramas de funcionalidad en un trimestre. Hay cuatro cosas que tienen que existir primero.
Un build y una suite de pruebas que terminen en unos diez minutos. Si el CI tarda 40 minutos, los desarrolladores agrupan cambios, y agrupar anula el modelo.
Pruebas que fallen por razones reales. Una suite inestable enseña a la gente a reintentar y fusionar igualmente.
Un proceso de revisión rápido y honesto. DORA señala la revisión de código pesada y asíncrona como un obstáculo habitual, porque empuja a los desarrolladores a agrupar trabajo.
Una forma de enviar trabajo incompleto con seguridad. Es el tema de la siguiente sección.
Si te saltas cualquiera de estas, el trunk se convierte en el lugar donde se acumulan las roturas, en lugar de ser el lugar donde se detectan.
¿Cómo fusionar trabajo sin enviarlo a producción?
Es la pregunta que hace todo escéptico, y tiene una respuesta aburrida: separas el despliegue de la liberación. El código llega a producción apagado, y un flag decide quién lo ve.
// checkout.ts
import { flags } from "./flags";
export async function renderCheckout(user: User) {
if (await flags.isEnabled("new-payment-flow", { userId: user.id })) {
return renderNewPaymentFlow(user); // fusionado en trunk, apagado por defecto
}
return renderLegacyCheckout(user);
}El flujo nuevo se fusiona el primer día, detrás de un flag desactivado. Lo activas para usuarios internos, luego para el 1 % de los usuarios, luego para el 10 %, con una puerta de SLO en cada paso. Si la tasa de errores supera el presupuesto, el flag se apaga y el cambio queda revertido sin necesidad de un despliegue. Los equipos que evalúan servicios de flags alojados suelen empezar con LaunchDarkly, aunque el patrón funciona con cualquier proveedor o con un almacén de configuración propio.
La segunda técnica es el branch by abstraction, para refactorizaciones grandes. Introduces una interfaz, diriges a los llamadores a través de ella, construyes la nueva implementación detrás y cambias cuando esté lista. Sin rama de larga vida y sin fusión de big-bang.

El coste honesto: los flags son deuda con vida media
Nadie en el circuito de conferencias quiere hablar de esto. Cada flag que añades es un condicional en producción que alguien tiene que eliminar. Hemos visto equipos de 80 ingenieros arrastrar varios cientos de flags obsoletos, cada uno una rama de código que nadie puede probar a fondo.
Trata los flags como elementos de vida corta por contrato. Asigna a cada uno un responsable y una fecha de caducidad en el momento de crearlo. Lanza una alerta sobre los flags que superen su caducidad. Borra la ruta de código muerta en el mismo pull request que elimina el flag.
El riesgo combinatorio también es real. Diez flags booleanos independientes dan 1.024 configuraciones posibles, y nunca vas a probarlas todas. Mantén pocas interacciones entre flags y separa los flags de liberación de los interruptores operativos de larga vida, como los kill switches.
Estrategias de release sobre trunk
Hay dos formas habituales de cortar una release desde trunk, y ninguna exige una rama de larga vida.
Liberar directamente desde trunk. Cada commit en verde es candidato. Los fallos se corrigen hacia delante, con un commit nuevo, y no parcheando una rama antigua. Esto encaja con equipos con pruebas automatizadas sólidas y despliegues rápidos.
Cortar una rama de release justo a tiempo. Ramificas desde un commit del trunk que sabes que está bien, lo endureces, lo despliegas y la eliminas. Las correcciones entran primero en el trunk y se trasladan de vuelta con cherry-pick. Esto encaja con equipos con puertas de release más lentas o con aprobaciones reguladas.
Cuál elijas depende de tu tiempo de detección. Si puedes notar un despliegue malo en cinco minutos y revertirlo en dos, corrige hacia delante. Si tu tiempo medio de detección es de una hora, una rama de release te da un lugar donde apoyarte.

La observabilidad es la otra mitad del trato
El trunk based development aumenta la frecuencia de despliegue, y con ella el número de momentos en los que algo puede salir mal. El modelo solo funciona si ves una regresión a los pocos minutos de una fusión. Eso significa tasas de error, percentiles de latencia y saturación vinculados a una release concreta, no a un dashboard que alguien revisa el lunes.
Una prueba útil: después de una fusión, ¿puedes responder "¿este cambio ha movido el p99 o la tasa de errores?" sin abrir cinco pestañas? Si no es así, no estás listo para fusionar diez veces al día.
Sea cual sea tu stack, el requisito es el mismo: marcadores de despliegue en tus gráficas, alertas de burn rate de SLO y una ruta de revert que una persona cansada pueda ejecutar a las 3 de la mañana sin pensar.
Trunk based development frente a GitFlow y GitHub Flow
Estos tres enfoques se confunden con frecuencia, así que sepáralos por una propiedad: cuánto tiempo permanece el trabajo fuera de la rama compartida.
GitFlow mantiene una rama develop, ramas de funcionalidad, ramas de release y ramas de hotfix. El trabajo puede aislarse durante semanas. Se diseñó para releases versionadas y programadas, y se nota cuando intentas desplegar diez veces al día.
GitHub Flow está cerca del trunk. Ramas de vida corta, pull requests, fusión a main y despliegue. La diferencia que marca la referencia está sobre todo en de dónde salen las releases.
El trunk based development es el más estricto de los tres con la vida de las ramas, y asume flags de funcionalidad o branch by abstraction para todo lo que no pueda enviarse en un único cambio pequeño.
Si tu equipo ya usa GitHub Flow con ramas que viven menos de dos días, estás más cerca del trunk de lo que crees. La brecha suele estar en la disciplina con los flags y en la latencia de revisión, no en las herramientas.
Qué métricas DORA se mueven primero
Instrumenta estas métricas antes de empezar, o discutirás después a base de sensaciones. La frecuencia de despliegue y el lead time for changes responden primero, porque los lotes más pequeños fluyen más rápido por el pipeline. La tasa de fallos en cambios y el tiempo de restauración vienen después, y dependen de tu observabilidad y de tu ruta de revert más que de la estrategia de ramas.
No conviertas los números en una evaluación de personas. Describen un sistema. Cuando suba el lead time, mira primero la cola de revisión y la duración del CI, y solo después a las personas.
Cuándo el trunk based development es la decisión equivocada
Descártalo, o al menos pospónlo, en algunos casos. Sé honesto sobre en cuál estás.
Tu suite de pruebas tarda una hora y no puedes paralelizarla. Vas a agrupar cambios, y agrupar rompe el modelo.
Entregas artefactos versionados a clientes que se quedan años en versiones antiguas. Necesitas ramas de mantenimiento. Es legítimo, y aun así puedes integrar a diario en el trunk.
No tienes sistema de flags ni ganas de construirlo. El trabajo a medio terminar se filtrará a las releases.
Tu equipo no confía en el build. Arregla primero las pruebas. El trunk no lo hará por ti.
El trunk based development tampoco garantiza nada. El hallazgo de DORA es una correlación con datos de 2016 y 2017, en los que los equipos que siguen estas prácticas muestran mejor rendimiento de entrega y operativo. No dice que cambiar el nombre de tus ramas arregle tu pipeline.
Cómo empezar sin una migración de big-bang
No anuncies una política. Mide primero y reduce después.
Registra la vida actual de tus ramas y el tamaño mediano de tus pull requests. Esas son tus cifras base.
Fija un límite, por ejemplo ninguna rama con más de dos días, y hazlo visible en un dashboard.
Arregla la parte más lenta del CI. Si el build tarda 30 minutos, nada más importa todavía.
Introduce un flag para una funcionalidad real. Envíala apagada y retira el flag dentro de un sprint.
Elimina los code freezes al final, cuando tu ruta de revert ya se haya probado en situaciones reales.
Revisa de nuevo dentro de un mes. Las cifras que se mueven primero suelen ser el tamaño de los pull requests y el tiempo hasta la fusión. La tasa de fallos en cambios tarda más, y a veces empeora antes de mejorar, porque por fin estás viendo las roturas antes.
¿Qué diría tu post-mortem sobre tu modelo de ramas?
¿Qué dirá el post-mortem? Esa es la pregunta útil antes de desplegar. Si tu última incidencia vino de una fusión que nadie pudo revisar, de una rama que divergió durante tres semanas o de una release que empaquetaba cuarenta cambios, ya sabes dónde vence la deuda.
Mira tus últimas tres caídas. ¿En cuántas hubo una integración grande y tardía? Ese número es tu caso de negocio.