5 alternativas a GitHub Actions para equipos de frontend
Compara cinco alternativas a GitHub Actions para equipos frontend: CircleCI, Buildkite, Jenkins, Woodpecker CI y Dagger, con ejemplos y orientación.
Las mejores alternativas a GitHub Actions para equipos de frontend son CircleCI para CI completamente alojada, Buildkite para un plano de control alojado que se ejecuta sobre agentes alojados o autoalojados, Jenkins y Woodpecker CI para CI completamente autoalojada, y Dagger para pipelines como código que se ejecutan igual en un portátil que en cualquier CI.
El detonante habitual es una factura llena de minutos de runner, un pull request esperando en una cola o un workflow que solo falla en los runners de GitHub y nunca en tu máquina. Este artículo da por hecho que ya conoces el modelo de workflows de GitHub Actions. Compara cinco opciones según los mismos tres criterios: a quién le conviene cada una, dónde se ejecutan sus jobs y cómo es un job de instalación, lint, test y build para un frontend en Node.
Conclusiones clave
- Si cada job de CI solo llama a
npm ci,npm run lint,npm testynpm run build, cambiar de herramienta de CI implica reescribir unas pocas líneas de YAML, no la lógica del pipeline. - Buildkite aloja la orquestación mientras los jobs se ejecutan en agentes: Linux alojado por Buildkite, macOS alojado por Buildkite en los planes de pago o máquinas que gestiona tu equipo.
- CircleCI es una CI alojada que se configura en
.circleci/config.ymly admite runners autoalojados en todos los planes, incluido el Free. - Jenkins y Woodpecker son autoalojados. Dejas de pagar por minuto y empiezas a pagar por servidores y mantenimiento.
- Dagger no es un servicio de CI. Es código de pipeline que se ejecuta en local y dentro de cualquier CI que ya utilices.
¿Por qué los equipos de frontend buscan alternativas a GitHub Actions?
Los equipos de frontend suelen abandonar GitHub Actions por uno de estos cuatro motivos: los minutos de los runners alojados cuestan demasiado, los runners alojados se quedan en cola, necesitan ejecutar agentes en su propio hardware o no pueden reproducir un pipeline de CI/CD en local. Revisa el segundo motivo antes de migrar. Si los runners alojados en cola son tu único problema, los runners autoalojados de GitHub Actions pueden solucionarlo sin cambiar de herramienta. GitLab CI/CD merece la pena sobre todo si también vas a trasladar tus repositorios; su configuración se explica en Pipelines de GitLab CI/CD.
Para que la comparación sea justa, coloca la lógica de build en package.json, de modo que todas las herramientas de CI llamen a los mismos scripts:
{
"scripts": {
"lint": "eslint .",
"test": "vitest run",
"build": "vite build"
}
}
Sustitúyelos por los comandos propios de tu framework. En cada uno de los ejemplos siguientes, la configuración de CI hace una sola cosa: ejecuta npm ci y después estos tres scripts.
Buildkite
Buildkite es adecuado para equipos que quieren una orquestación alojada pero necesitan controlar las máquinas que ejecutan sus jobs. Buildkite admite ambos modelos: agentes que ejecutas tú mismo y agentes que Buildkite aloja por ti. Los agentes Linux alojados por Buildkite están disponibles en todos los planes, incluido el Free, que se limita al tamaño de máquina pequeño. Los agentes macOS alojados por Buildkite requieren un plan Pro o Enterprise. Los agentes autoalojados consultan periódicamente a Buildkite en busca de trabajo, por lo que no necesitas abrir ningún puerto de entrada. Buildkite ofrece una cuenta gratuita para empezar.
# .buildkite/pipeline.yml
steps:
- label: "Install, lint, test, build"
commands:
- npm ci
- npm run lint
- npm test
- npm run build
plugins:
- docker#v5.14.0:
image: "node:<your-node-version>"
El plugin de Docker ejecuta los comandos dentro de una imagen de Node, así que el agente solo necesita Docker. Si Node ya está instalado en el agente, puedes eliminar el bloque plugins.
Veredicto: Buildkite es la mejor opción cuando quieres ser dueño de tu capacidad de cómputo sin gestionar un servidor de CI. La contrapartida es que tú administras la flota de agentes, salvo que utilices agentes alojados.
CircleCI
CircleCI es adecuado para equipos que quieren un servicio completamente alojado con la mínima infraestructura. CircleCI está pensado ante todo como servicio alojado, y además ofrece runners autoalojados en todos los planes, incluido el Free. Por defecto, tu código se ejecuta en la infraestructura de CircleCI. La introducción a la configuración de CircleCI señala la 2.1 como la versión más reciente.
# .circleci/config.yml
version: 2.1
jobs:
build:
docker:
- image: cimg/node:<full.node.version>
steps:
- checkout
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
workflows:
ci:
jobs:
- build
Fija cimg/node a la versión completa de Node de tu proyecto. CircleCI también admite caché de dependencias, pero aquí se omite para que el ejemplo sea breve. Los errores de YAML son una causa habitual de que falle el primer push a CircleCI, así que conviene pasar el archivo por el validador de YAML de OpenReplay para detectar errores de sintaxis antes de hacer commit.
Veredicto: CircleCI es el sustituto más directo de GitHub Actions. Tiene sentido si el problema son los minutos y las colas, pero sigues sin querer gestionar servidores.
Jenkins
Jenkins es adecuado para equipos con requisitos estrictos de infraestructura on-premises y alguien con tiempo para mantenerlo. Jenkins solo se puede autoalojar. El software es libre y de código abierto, pero el coste pasa de la facturación por minuto a los servidores, plugins y actualizaciones que mantiene tu equipo. Los pipelines se definen en un Jenkinsfile escrito con la sintaxis declarativa de Pipeline:
pipeline {
agent any
stages {
stage('Install') { steps { sh 'npm ci' } }
stage('Lint') { steps { sh 'npm run lint' } }
stage('Test') { steps { sh 'npm test' } }
stage('Build') { steps { sh 'npm run build' } }
}
}
agent any asume que Node está instalado en el agente que recoja el job, sea cual sea.
Veredicto: elige Jenkins solo cuando el autoalojamiento sea un requisito ineludible. Para la mayoría de los equipos de frontend, el mantenimiento cuesta más que los minutos que ahorra.
Woodpecker CI
Woodpecker CI es adecuado para equipos pequeños que quieren una CI autoalojada y ligera, con un YAML que les resulte familiar. Woodpecker CI es autoalojado, y cada step ejecuta sus comandos dentro del contenedor indicado en ese step, tal como establece la sintaxis de workflows. Los workflows pueden ubicarse en un directorio .woodpecker/, con un workflow por archivo.
# .woodpecker/ci.yaml
steps:
- name: install
image: node:<your-node-version>
commands:
- npm ci
- name: lint
image: node:<your-node-version>
commands:
- npm run lint
- name: test
image: node:<your-node-version>
commands:
- npm test
- name: build
image: node:<your-node-version>
commands:
- npm run build
Dividir el trabajo en cuatro steps no implica instalar cuatro veces. Por defecto, los steps se ejecutan en secuencia y el workspace clonado se monta en cada uno de ellos, de modo que la carpeta node_modules generada en install sigue disponible en build. Con woodpecker-cli y un backend compatible instalados, puedes ejecutar un workflow en local con woodpecker-cli exec antes de hacer push.
Veredicto: para autoalojar, Woodpecker CI es una opción más sencilla que Jenkins. El inconveniente es que tú mismo gestionas el servidor y los agentes.
Dagger: pipelines como código, no un servicio de CI
Dagger no es un servicio de CI alojado ni sustituye a uno. Escribes el pipeline como código con un SDK de Dagger, y ese mismo código se ejecuta en un portátil y dentro de cualquier sistema de CI, incluido GitHub Actions. La documentación de los SDK abarca Go, Python, TypeScript, Java, PHP y Elixir, además de Dang, el lenguaje de scripting propio de Dagger. Este es el mismo job en TypeScript, usando un módulo creado con dagger init --sdk=typescript --name=frontend-ci:
import { dag, Directory, object, func } from "@dagger.io/dagger"
@object()
class FrontendCi {
@func()
async check(source: Directory, nodeVersion: string): Promise<string> {
return await dag
.container()
.from(`node:${nodeVersion}`)
.withMountedDirectory("/src", source)
.withWorkdir("/src")
.withExec(["npm", "ci"])
.withExec(["npm", "run", "lint"])
.withExec(["npm", "test"])
.withExec(["npm", "run", "build"])
.stdout()
}
}
Ejecútalo en local con dagger call check --source=. --node-version=<your-node-version>. Tu job de CI existente pasa a ejecutar ese mismo comando y nada más. Si una ejecución local pasa, la ejecución en CI realiza exactamente los mismos pasos en contenedor. El coste es un SDK y un motor más que el equipo tiene que aprender.
Estos comandos corresponden a Dagger 0.x. Dagger 1.0, anunciado en beta en octubre de 2026, los renombra: dagger module init crea un módulo y dagger call pasa a ser dagger api call. El código TypeScript no cambia.
¿Cómo elegir una alternativa a GitHub Actions?
La alternativa adecuada a GitHub Actions depende de dónde quieras que se ejecuten los jobs:
- Si quieres una CI completamente alojada sin nada que operar, usa CircleCI. Su configuración se corresponde estrechamente con la que ya tienes.
- Si quieres orquestación alojada sobre máquinas propias o alojadas por el proveedor, usa Buildkite, sobre todo si necesitas builds en macOS.
- Si el autoalojamiento es obligatorio y cuentas con personal para mantenerlo, usa Jenkins.
- Si el autoalojamiento es obligatorio y quieres algo ligero, usa Woodpecker CI.
- Si el verdadero problema es «funciona en local, falla en CI», añade Dagger y mantén cualquiera de las herramientas anteriores, o el propio GitHub Actions, como ejecutor.
- Si el único problema es el tiempo de espera en cola, prueba primero los runners autoalojados de GitHub Actions.
Tanto el backend de Docker de Woodpecker como Dagger necesitan un runtime de contenedores. Si Docker Desktop no encaja con tus máquinas, Dagger también funciona con Podman y nerdctl, y Woodpecker puede ejecutarse en Kubernetes o directamente en el host con su backend local.
Elijas la herramienta que elijas, empieza por trasladar toda la lógica de build a scripts de npm. Después, prueba la alternativa en una sola rama, en paralelo con GitHub Actions, y compara los resultados durante una semana antes de hacer el cambio definitivo.
Preguntas frecuentes
¿GitHub cobra por minuto el uso de runners autoalojados en GitHub Actions?
No. GitHub no factura tarifas por minuto por el uso de runners autoalojados, así que el coste corresponde a las máquinas en las que los ejecutas. En diciembre de 2025, GitHub anunció un cargo de plataforma de 0,002 dólares estadounidenses por minuto para los runners autoalojados a partir del 1 de marzo de 2026, pero después lo aplazó para reevaluar su enfoque. Consulta la documentación de facturación de Actions de GitHub antes de basar una comparación de costes en cualquiera de esas cifras.
¿Puedo ejecutar un job de CircleCI en local antes de hacer push?
Sí, de uno en uno. La CLI de CircleCI ejecuta un único job dentro de Docker en tu máquina con circleci local execute. Los workflows no se ejecutan en local y el executor machine no es compatible. Para una configuración de la versión 2.1, primero exporta la configuración procesada con circleci config process y después pasa ese archivo a circleci local execute usando el flag -c y el nombre del job.
¿Woodpecker CI funciona con repositorios alojados en GitHub?
Sí. Woodpecker es compatible con GitHub, incluido GitHub Enterprise, así como con GitLab, Gitea, Forgejo y Bitbucket Cloud. Registras una aplicación OAuth en la forja y pasas su client ID y su secret al servidor de Woodpecker mediante variables de entorno como WOODPECKER_GITHUB_CLIENT y WOODPECKER_GITHUB_SECRET. Los repositorios siguen en GitHub, Woodpecker le devuelve el estado de los pipelines y solo el servidor y los agentes se ejecutan en tu infraestructura.
¿Cómo ejecuto una función de Dagger desde un workflow existente de GitHub Actions?
Añade un step que use la action oficial dagger/dagger-for-github después de actions/checkout. La action instala la CLI de Dagger, inicia un Dagger Engine en el runner y llama a tu función. Establece verb en call y pasa los mismos argumentos que usas en local, como check con tu directorio de código fuente y tu versión de Node. La lógica del pipeline permanece en el módulo, así que, si más adelante abandonas GitHub Actions, solo cambia este fino envoltorio.