Guía para escribir un archivo CHANGELOG.md siguiendo el estándar Keep a Changelog, con versionado semántico, categorías de cambios y ejemplos completos
Un changelog es un archivo que registra los cambios relevantes de cada versión de un proyecto, ordenados de la más reciente a la más antigua. Se escribe en Markdown, se llama CHANGELOG.md y vive en la raíz del repositorio, junto al README.
Suena trivial, pero es de las pocas cosas que separan un proyecto que la gente puede actualizar con confianza de uno donde cada versión nueva es una lotería. Esta guía cubre el estándar que se usa hoy, cómo relacionarlo con el número de versión y cómo redactar las entradas para que sirvan de algo.
Un changelog es un documento para personas. Explica qué ha cambiado en cada versión y qué implica ese cambio para quien usa el proyecto.
Eso lo diferencia de dos cosas con las que se confunde a menudo. No es el historial de Git, que registra cada commit con detalle técnico y está pensado para quien desarrolla. Y no son las notas de la release, que suelen ser un texto promocional centrado en lo llamativo.
La prueba del algodón: si alguien va a actualizar de la versión anterior a la tuya, ¿tu changelog le dice lo que necesita saber antes de hacerlo? Si la respuesta es no, el archivo no está cumpliendo su función.
La tentación es obvia: ya tienes el historial, ¿por qué escribirlo otra vez? Porque un log de Git generado automáticamente produce algo así.
- fix typo
- wip
- merge branch feature/auth
- refactor user service
- fix tests
Nada de eso le sirve a quien usa el proyecto. Los commits describen el trabajo de quien programa, no las consecuencias para quien consume. Un changelog útil traduce ese trabajo a efectos observables.
Por eso el consejo estándar es escribirlo a mano, o al menos revisar a mano cualquier borrador generado. Es cinco minutos por versión y es la parte del proyecto con mejor relación entre esfuerzo y utilidad.
Existe una convención ampliamente adoptada llamada Keep a Changelog, que define cómo estructurar el archivo. No es un estándar oficial de ningún organismo, pero es lo que espera encontrar cualquiera que abra tu CHANGELOG.md.
El documento empieza con un encabezado de nivel uno y una nota que explica qué convenciones sigue. Después vienen los bloques de versión, del más reciente al más antiguo.
# Changelog
Todos los cambios notables de este proyecto se documentan en este archivo.
El formato sigue Keep a Changelog y el proyecto usa versionado semantico.
## [Sin publicar]
## [1.2.0] - 2026-08-15
### Anadido
- Soporte para exportar a PDF
### Corregido
- El buscador ignoraba los acentosCada versión es un encabezado de nivel dos con el número entre corchetes y la fecha en formato AAAA-MM-DD. Los corchetes no son decorativos: permiten definir el número como un enlace de referencia al final del archivo, apuntando a la comparación de versiones en el repositorio.
[1.2.0]: https://github.com/usuario/proyecto/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/usuario/proyecto/compare/v1.0.0...v1.1.0La fecha en formato ISO es importante porque evita la ambigüedad entre el orden británico y el estadounidense. Un 03/04/2026 significa cosas distintas según quién lo lea.
Arriba del todo, antes de la primera versión, conviene mantener una sección para los cambios que ya están en la rama principal pero todavía no se han publicado.
## [Sin publicar]
### Anadido
- Modo oscuro en el panel de ajustesSirve para dos cosas. Quien sigue el proyecto ve lo que viene, y tú acumulas las entradas según las vas haciendo en vez de intentar reconstruirlas el día de la publicación. Cuando llega el momento de publicar, renombras la sección con el número y la fecha, y creas una nueva sección vacía encima.
Dentro de cada versión, los cambios se agrupan en encabezados de nivel tres. La convención define seis categorías y conviene ceñirse a ellas en vez de inventar las tuyas.
| Categoría | Cuándo se usa |
|---|---|
| Añadido | Funcionalidades nuevas |
| Cambiado | Cambios en funcionalidades que ya existían |
| Obsoleto | Funcionalidades que se eliminarán en el futuro |
| Eliminado | Funcionalidades retiradas en esta versión |
| Corregido | Errores resueltos |
| Seguridad | Vulnerabilidades corregidas |
Solo se incluyen las categorías que tengan contenido. Si una versión solo corrige errores, tendrá únicamente el bloque de corregido.
La categoría de obsoleto es la que más se ignora y la más valiosa. Avisar con una versión de antelación de que algo va a desaparecer es la diferencia entre una migración ordenada y un montón de proyectos rotos. La de seguridad merece su propio bloque porque hay gente que solo actualiza cuando ve algo ahí.
El changelog y el número de versión son dos caras de lo mismo. El estándar habitual es el versionado semántico, que usa tres números separados por puntos.
MAYOR.MENOR.PARCHE
La regla es corta y se puede deducir directamente de las categorías del changelog.
De ahí sale una comprobación muy útil: si tu versión tiene entradas en eliminado pero solo has subido el número menor, algo no cuadra. El changelog te dice qué número te toca.
Mientras el primer número es cero, el proyecto se considera en desarrollo inicial y la convención permite romper la compatibilidad en cualquier momento. Publicar la 1.0.0 es el compromiso de dejar de hacerlo a la ligera, no una señal de que el proyecto ya está terminado.
Aquí es donde se gana o se pierde la utilidad del archivo, y la regla es escribir desde el punto de vista de quien usa el proyecto, no de quien lo programó.
Compara estas dos formas de contar el mismo cambio:
### Cambiado
- Refactorizado el modulo de autenticacion
### Cambiado
- Los tokens de sesion ahora caducan a los 30 dias en vez de a los 7.
Las sesiones activas se cerraran al actualizar.La primera describe el trabajo. La segunda describe la consecuencia, que es lo único que le importa a quien va a actualizar.
Algunas costumbres que ayudan:
El archivo va en la raíz del repositorio con el nombre CHANGELOG.md en mayúsculas, igual que el README y la licencia. GitHub y el resto de plataformas lo reconocen por ese nombre y lo muestran renderizado.
Desde el README conviene enlazarlo de forma visible, porque es donde la gente lo va a buscar.
Consulta el [CHANGELOG](CHANGELOG.md) para ver los cambios de cada version.Si publicas el proyecto como paquete, el mismo archivo suele alimentar las notas de cada versión de la plataforma correspondiente, así que escribirlo bien te ahorra hacerlo dos veces. Y si tu proyecto tiene documentación aparte, tiene sentido incluirlo también ahí, como explicamos en cómo documentar un proyecto con Markdown.
Hay herramientas que generan el changelog a partir de los mensajes de commit, siempre que estos sigan una convención estricta con prefijos del tipo feat: o fix:. Funcionan, y en proyectos con mucho movimiento ahorran trabajo real.
El punto a tener en cuenta es que la calidad del resultado nunca supera a la de los mensajes de commit. Si el equipo escribe commits pensando en el changelog, sale bien. Si no, sale un log de Git con otro formato. Un término medio que funciona: genera el borrador de forma automática y dedica cinco minutos a reescribir las entradas antes de publicar. Puedes integrarlo en tu flujo de integración continua, como vemos en automatizar tareas con Markdown.
Así queda un archivo real con varias versiones, incluyendo un cambio que rompe compatibilidad:
# Changelog
Todos los cambios notables de este proyecto se documentan en este archivo.
## [Sin publicar]
### Anadido
- Exportacion a formato EPUB
## [2.0.0] - 2026-08-20
### Eliminado
- Soporte para la API v1, marcada como obsoleta desde la 1.4.0.
Migra a la v2 siguiendo la guia de migracion del README.
### Cambiado
- La configuracion pasa de config.json a config.yaml.
El comando de arranque convierte el archivo antiguo automaticamente.
### Seguridad
- Corregida una vulnerabilidad en la validacion de los tokens de sesion.
## [1.4.0] - 2026-06-10
### Anadido
- Soporte para plantillas personalizadas
### Obsoleto
- La API v1 dejara de funcionar en la version 2.0.0
### Corregido
- Los acentos se mostraban mal al exportar a PDF
[Sin publicar]: https://github.com/usuario/proyecto/compare/v2.0.0...HEAD
[2.0.0]: https://github.com/usuario/proyecto/compare/v1.4.0...v2.0.0
[1.4.0]: https://github.com/usuario/proyecto/compare/v1.3.0...v1.4.0Fíjate en cómo la entrada de eliminado dice qué hacer, y en que la funcionalidad retirada en la 2.0.0 ya se había anunciado como obsoleta en la 1.4.0. Eso es un changelog haciendo su trabajo.
Ya tienes el criterio. Para pasar a la práctica:
👋 Hola! Soy Edu, me encanta crear cosas y he redactado este tutorial. Si te ha resultado útil, el mayor favor que me podrías hacer es el de compatirlo en Twitter.
Sígueme en Twitter para estar al día con mi contenido. 😊