Blog

Cómo configurar Lefthook y commitlint en tus proyectos

Aprende a configurar Lefthook junto a commitlint para automatizar linters, formateadores y validación de commits en cualquier proyecto JavaScript o TypeScript.

  • Git
  • Herramientas

Introducción

Lefthook es una alternativa a Husky notablemente más rápida, escrita en Go. Puede instalarse como binario independiente o como paquete de Node.js. En esta guía usaremos la segunda opción para que quede declarado como dependencia del proyecto y cualquier persona que lo clone lo tenga disponible automáticamente tras instalar dependencias.

Se asume que ya conoces qué son los git hooks y para qué sirven. A lo largo de esta guía configuraremos los hooks pre-commit, commit-msg y pre-push, que son los más utilizados en el día a día, aunque en la documentación oficial encontrarás todos los hooks disponibles.

Puedes usar cualquier gestor de paquetes. En los ejemplos usaré pnpm.

Instalación

Instala las siguientes dependencias de desarrollo:

Terminal window
pnpm add -DE lefthook@latest @commitlint/cli@latest @commitlint/config-conventional@latest

Se instalan las versiones exactas más recientes, sin carets (^), como dependencias de desarrollo.

Nota: Si usas pnpm, asegúrate de agregar lefthook a onlyBuiltDependencies en pnpm-workspace.yaml y a pnpm.onlyBuiltDependencies en tu package.json raíz, de lo contrario el script postinstall del paquete lefthook no se ejecutará y los hooks no se instalarán.

pnpm-workspace.yaml
onlyBuiltDependencies:
- lefthook

Y agrega lefthook a la sección onlyBuiltDependencies en tu package.json raíz:

package.json
{
...
"pnpm": {
"onlyBuiltDependencies": [
"lefthook"
]
}
}

Configuración de commitlint

Commitlint valida que los mensajes de commit sigan el estándar de Conventional Commits, lo que facilita generar changelogs automáticos y mantener un historial legible.

Crea el archivo de configuración en la raíz del proyecto:

commitlint.config.js
export default { extends: ["@commitlint/config-conventional"] }

Configuración de Lefthook

Para este ejemplo asumiré que el proyecto tiene Biome como linter y formateador, con los siguientes scripts en package.json:

package.json
{
...
"scripts": {
"format": "biome format",
"lint": "biome lint",
"check": "biome check",
}
}

Crea el archivo lefthook.yml en la raíz del proyecto:

lefthook.yml
# Ejecuta linters y formateadores en los archivos preparados antes de confirmar los cambios
pre-commit:
parallel: false # Ejecutar todos los comandos de forma concurrente
commands:
check:
glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}"
run: pnpm run check --write --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {staged_files}
stage_fixed: true
# Validar mensajes de commit
commit-msg:
commands:
commitlint:
run: pnpm commitlint --edit {1}
# Verificar el formato y el lint antes de hacer push
pre-push:
commands:
check:
glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}"
run: npx @biomejs/biome check --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {push_files}

Cada sección corresponde a un hook de Git:

  • pre-commit — se ejecuta sobre los archivos en staging antes de crear el commit. La opción stage_fixed: true re-agrega automáticamente los archivos que Biome haya corregido.
  • commit-msg — valida el mensaje de commit con commitlint antes de registrarlo.
  • pre-push — revisa todos los archivos modificados en el push, sin aplicar correcciones automáticas.

La opción parallel controla si los comandos dentro de un hook se ejecutan en paralelo o en secuencia. Como en este ejemplo pre-commit solo tiene un comando, el valor false (que es el predeterminado) no cambia nada, pero lo incluyo para que sea explícito si luego agregas más comandos.

Puedes ampliar esta configuración según las necesidades del proyecto: tests unitarios en pre-commit, pruebas end-to-end en pre-push, generación de tipos, etc. Consulta la documentación oficial de Lefthook para ver todas las opciones disponibles.