Bruno: la alternativa open source a Postman que vive en Git

Por qué los equipos cambian Postman por Bruno: colecciones en archivos de texto versionados en Git, sin cuenta y sin nube. Qué ganas, qué pierdes y cómo migrar.

Pregunta incómoda para la próxima reunión de ingeniería: ¿dónde vive la colección de requests de tu API? La respuesta honesta, en muchos equipos, es “en la cuenta de Postman de alguien”. No en el repositorio, no en un backup, en ningún lugar que la empresa controle. Cuando esa persona se va, la documentación viva de cómo llamar a tu propio sistema se va con ella, y alguien va a reconstruir a mano el payload de aquel endpoint de pagos.

Este texto no es una lista de diez alternativas a Postman con puntuación de una a cinco estrellas. Es un argumento sobre un problema concreto — colecciones de API que no viven junto al código — y sobre la herramienta que lo resuelve por diseño, no por configuración. Si tu molestia con Postman es el precio o la telemetría, el razonamiento ayuda; pero el caso fuerte de Bruno es otro.

Bruno es un cliente de API que guarda cada request como un archivo de texto dentro de la carpeta de tu proyecto, versionado por Git, sin cuenta y sin nube obligatoria.

El problema no es el precio, es dónde vive la colección

Postman es una herramienta buena y madura. Lo que cambió no fue su calidad, sino su arquitectura: desde la versión 10 el producto gira alrededor de la cuenta y del workspace en la nube. El modo offline más usado, el Scratch Pad, quedó descontinuado — la propia Postman anunció su cierre, con corte para nuevas descargas el 15 de mayo de 2023 y fin del modo deprecado el 15 de septiembre del mismo año, sustituido por un cliente ligero para quien solo quiere disparar requests.

El efecto colateral es organizativo, no técnico. Cuando la colección vive en la cuenta de alguien:

  • No pasa por review. Nadie abre un pull request para discutir que cambió la cabecera de autenticación.
  • Se desincroniza del código. El endpoint se renombró el viernes; la colección sigue con el nombre viejo ocho meses después.
  • Es de quien la creó, no de la empresa. Es un riesgo de continuidad a plena vista.
  • Puede cargar secretos. Un token de staging pegado en un environment que sincroniza a un servidor de terceros es una decisión de seguridad que nadie tomó conscientemente.

Ninguno de esos problemas se resuelve pagando más caro. Se resuelven cambiando el lugar donde está el archivo.

Cómo guarda las cosas Bruno

Bruno escribe cada request como un archivo de texto con extensión .bru, dentro de una carpeta de tu proyecto. Una colección es un directorio; una carpeta en la interfaz es una carpeta en disco. No hay base de datos local opaca, no hay sincronización, no hay login. El repositorio oficial, que supera las 40 mil estrellas en GitHub, describe exactamente eso: un cliente de API git-native.

Un archivo .bru se ve así:

meta {
  name: Crear pedido
  type: http
}

post {
  url: {{base_url}}/v1/orders
  body: json
}

headers {
  Authorization: Bearer {{token}}
}

body:json {
  {
    "sku": "ABC-123",
    "quantity": 2
  }
}

Es legible por una persona y, lo que importa más, legible por git diff. Cuando alguien cambia el cuerpo de la petición, el pull request muestra la línea que cambió. La colección deja de ser un adjunto binario y pasa a ser código: revisable, con historial, con autor y con fecha.

Eso cambia un hábito práctico: la colección entra en el mismo repositorio del servicio que prueba. Quien clona el proyecto ya tiene los requests. Quien entra al equipo el lunes abre la carpeta y ve cómo se llama al sistema, sin pedir invitación a ningún workspace.

Dónde poner la carpeta en el repositorio

La decisión de layout es pequeña y define si el patrón cuaja o no. Lo que funciona en la práctica es que la colección viva en la raíz del servicio, junto al código que prueba:

servicio-pedidos/
├── src/
├── api/                    ← la colección
│   ├── bruno.json
│   ├── environments/
│   │   ├── local.bru
│   │   └── staging.bru     ← solo nombres de variable, nunca valores
│   └── pedidos/
│       ├── crear-pedido.bru
│       └── cancelar-pedido.bru
└── .gitignore

Dos reglas evitan casi todo el dolor posterior. Primera: una colección por servicio, no una colección monolítica de toda la empresa — una colección compartida entre equipos se convierte en el cuello de botella de siempre, con conflictos de merge en un archivo del que nadie es dueño. Segunda: el nombre del archivo es el nombre del request, en kebab-case, porque así aparece en el diff. Quien revisa el pull request lee “crear-pedido.bru” y ya sabe qué mirar.

Licencia: qué es gratuito exactamente

Vale ser específico, porque “open source” se volvió una palabra elástica. La aplicación de escritorio de Bruno se distribuye bajo licencia MIT, la permisiva clásica, sin cláusula de uso comercial restringido. La ejecutas, la modificas y la usas dentro de la empresa sin pedir autorización.

La empresa detrás del proyecto monetiza con un plan de pago, con funciones adicionales y soporte corporativo, y existió una edición vitalicia de pago que fue descontinuada. Nada de eso es requisito para el uso normal: no hay límite de requests, de colecciones ni de personas, porque no existe un servidor contando. Es la diferencia entre un producto gratis y un producto que no tiene cómo cobrar por volumen.

Bruno en CI: bru run

La parte que suele decidir la adopción no es la interfaz, es la CLI. El comando bru run ejecuta una colección entera desde la terminal, corre los tests y assertions escritos en JavaScript y devuelve un exit code, que es lo que un pipeline necesita para hacer fallar el build. La documentación de la CLI cubre generación de reportes en JSON, JUnit y HTML, además de guías para GitHub Actions, Jenkins, GitLab CI y Azure DevOps.

La ganancia aquí es sutil y grande: el mismo artefacto sirve para los dos usos. El request que disparas a mano para depurar es el request que corre en el pipeline. No existe una colección “de desarrollo” y una suite separada “de contrato” que divergen en tres meses.

Un test típico ocupa pocas líneas:

test("crea pedido y devuelve id", function () {
  expect(res.getStatus()).to.equal(201)
  expect(res.getBody().id).to.be.a("string")
})

Secretos: la parte donde es fácil equivocarse feo

Poner la colección en el repositorio aumenta la probabilidad de que alguien commitee un token. El patrón correcto es corto y no es negociable: en el archivo de entorno versionado va solo el nombre de la variable; el valor viene de un archivo local ignorado por .gitignore o de un gestor de secretos, y se inyecta como variable de entorno al ejecutar.

En CI, el valor viene del almacén de secretos del propio pipeline. En ningún momento el secreto necesita existir dentro de un archivo .bru.

Vale repetir lo que se suele aprender del modo caro: un token que entró en un commit ya está filtrado, aunque lo borres en el commit siguiente. El historial sigue ahí, y cualquiera que ya haya clonado tiene una copia. La única respuesta es rotar la credencial.

Qué pierdes al salir de Postman

Una migración honesta declara su costo. Lo que Postman hace mejor:

  • Colaboración lista. Workspace compartido, historial, comentarios y permisos vienen gratis con la cuenta. En Bruno, colaborar es tu flujo de Git. Para un equipo que ya vive en pull requests es una ventaja; para un equipo con gente de producto o QA que no usa Git, es fricción real.
  • Documentación publicable. Generar un portal de API a partir de la colección y mandar el enlace a un partner es un caso que Postman resuelve con un clic.
  • Ecosistema y mocks. Servidores de mock, monitores e integraciones listas llevan años de ventaja.
  • Scripts existentes. La importación trae bien requests y entornos; los scripts de pre-request y los tests que dependen de APIs propias de Postman suelen necesitar revisión manual.

Si tu uso principal es justamente colaborar con gente fuera de ingeniería, Bruno resuelve menos de lo que promete.

Cómo decidir en una tarde

No migres a todo el equipo de una vez: eso convierte una elección reversible en un proyecto. Elige un servicio, preferiblemente uno que ya tenga pipeline. Exporta la colección de Postman, impórtala en Bruno, deja la carpeta dentro del repositorio del servicio, apunta los secretos a variables de entorno y añade un paso de bru run en CI.

Después de dos o tres semanas, haz las tres preguntas que importan: ¿alguien abrió un pull request modificando la colección? ¿El pipeline detectó una ruptura de contrato antes del deploy? ¿Quien entró al proyecto pudo llamar a la API sin pedirle acceso a nadie? Si las tres respuestas son sí, el patrón se demuestra solo y los demás servicios siguen detrás, sin reunión de decisión, que es como suelen ocurrir los buenos cambios de herramienta.

Servicios relacionados

Continúa con Pixelize

Conecta este tema con los servicios correctos — o habla con un consultor.