5 альтернатив GitHub Actions для фронтенд-команд
Сравните пять альтернатив GitHub Actions для frontend-команд: CircleCI, Buildkite, Jenkins, Woodpecker CI и Dagger. Примеры настройки и рекомендации.
Для фронтенд-команд лучшие альтернативы GitHub Actions таковы: CircleCI — полностью облачный CI; Buildkite — облачная управляющая плоскость (control plane), которая запускает задачи на облачных или собственных агентах; Jenkins и Woodpecker CI — полностью self-hosted CI; Dagger — пайплайны в виде кода, которые одинаково работают и на ноутбуке, и в любой CI-системе.
Обычно к поиску замены подталкивает одно из трёх: счёт, раздутый минутами раннеров, pull request, застрявший в очереди, или workflow, который падает только на раннерах GitHub и никогда — на вашей машине. Предполагается, что вы уже знакомы с моделью workflow в GitHub Actions. В статье пять вариантов сравниваются по трём критериям: кому каждый из них подходит, где выполняются задачи и как выглядит задача установки зависимостей, линтинга, тестирования и сборки для фронтенда на Node.
Основные выводы
- Если каждая CI-задача лишь вызывает
npm ci,npm run lint,npm testиnpm run build, то смена CI-инструмента сводится к правке нескольких строк YAML, а не к переписыванию логики пайплайна. - Buildkite берёт оркестрацию на себя, а задачи выполняются на агентах: облачных Linux-агентах Buildkite, облачных macOS-агентах Buildkite на платных тарифах или на машинах вашей команды.
- CircleCI — облачный CI, который настраивается в
.circleci/config.ymlи поддерживает self-hosted раннеры на всех тарифах, включая Free. - Jenkins и Woodpecker разворачиваются на собственной инфраструктуре. Вместо поминутной оплаты вы платите за серверы и их обслуживание.
- Dagger — не CI-сервис, а код пайплайна, который работает локально и внутри любой CI-системы, которую вы уже используете.
Почему фронтенд-команды ищут альтернативы GitHub Actions?
Обычно фронтенд-команды уходят с GitHub Actions по одной из четырёх причин: минуты облачных раннеров обходятся слишком дорого, облачные раннеры простаивают в очереди, нужно запускать агенты на собственном железе или не получается воспроизвести CI/CD-пайплайн локально. Прежде чем мигрировать, проверьте вторую причину. Если единственная проблема — очередь к облачным раннерам, её можно решить с помощью self-hosted раннеров GitHub Actions, не меняя инструмент. GitLab CI/CD стоит рассматривать в первую очередь, если вы готовы перенести туда и репозитории; его настройка описана в статье GitLab CI/CD pipelines.
Чтобы сравнение было честным, вынесите логику сборки в package.json, тогда каждый CI-инструмент будет вызывать одни и те же скрипты:
{
"scripts": {
"lint": "eslint .",
"test": "vitest run",
"build": "vite build"
}
}
Подставьте команды своего фреймворка. Во всех примерах ниже конфигурация CI делает только одно: запускает npm ci, а затем эти три скрипта.
Buildkite
Buildkite подходит командам, которым нужна облачная оркестрация, но важен контроль над машинами, на которых выполняются задачи. Buildkite поддерживает обе модели: агенты, которые вы запускаете сами, и агенты, которые Buildkite размещает за вас. Облачные Linux-агенты Buildkite доступны на всех тарифах, включая Free, где можно использовать только машины минимальной конфигурации. Облачные macOS-агенты Buildkite требуют тарифа Pro или Enterprise. Self-hosted агенты сами опрашивают Buildkite на наличие задач, поэтому открывать входящие порты не нужно. Для начала работы Buildkite предлагает бесплатный аккаунт.
# .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>"
Docker-плагин выполняет команды внутри образа Node, поэтому агенту нужен только Docker. Если Node уже установлен на агенте, блок plugins можно убрать.
Вердикт: Buildkite — лучший вариант, если вы хотите владеть вычислительными ресурсами, не поддерживая собственный CI-сервер. Обратная сторона — управлять парком агентов придётся самостоятельно, если только вы не используете облачные агенты.
CircleCI
CircleCI подходит командам, которым нужен полностью облачный сервис с минимумом инфраструктуры. CircleCI изначально ориентирован на облако, но также предлагает self-hosted раннеры на всех тарифах, включая Free. По умолчанию ваш код выполняется на инфраструктуре CircleCI. В вводном руководстве по конфигурации CircleCI актуальной указана версия 2.1.
# .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
Зафиксируйте в cimg/node полную версию Node, используемую в проекте. CircleCI поддерживает и кеширование зависимостей, но здесь оно опущено ради краткости примера. Ошибки в YAML — частая причина того, что первый пуш в CircleCI завершается неудачей, поэтому имеет смысл прогнать файл через валидатор YAML от OpenReplay, чтобы отловить синтаксические ошибки до коммита.
Вердикт: CircleCI — наиболее близкая замена GitHub Actions по принципу «один в один». Он оправдан, если проблема в минутах и очередях, но поддерживать серверы вы по-прежнему не хотите.
Jenkins
Jenkins подходит командам со строгими требованиями к on-premises-развёртыванию и с человеком, у которого есть время его поддерживать. Jenkins разворачивается только на собственной инфраструктуре. Сам он бесплатный и с открытым исходным кодом, но затраты смещаются с поминутной оплаты на серверы, плагины и обновления, которые обслуживает ваша команда. Пайплайны описываются в файле Jenkinsfile с использованием декларативного синтаксиса 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 предполагает, что Node установлен на любом агенте, который возьмёт задачу.
Вердикт: выбирайте Jenkins, только если self-hosting — жёсткое требование. Для большинства фронтенд-команд затраты на его поддержку превышают экономию на минутах.
Woodpecker CI
Woodpecker CI подходит небольшим командам, которым нужен лёгкий self-hosted CI с привычным YAML. Woodpecker CI разворачивается на собственной инфраструктуре, и каждый шаг выполняет свои команды внутри контейнера, указанного в этом шаге, как описано в синтаксисе workflow. Workflow можно размещать в каталоге .woodpecker/, по одному на файл.
# .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
Разделение работы на четыре шага не означает четырёхкратной установки зависимостей. По умолчанию шаги выполняются последовательно, а рабочее пространство с извлечённым кодом монтируется в каждый шаг, поэтому каталог node_modules, созданный на шаге install, остаётся доступным и на шаге build. Если установлены woodpecker-cli и поддерживаемый бэкенд, можно запустить workflow локально командой woodpecker-cli exec перед пушем.
Вердикт: для self-hosting Woodpecker CI проще, чем Jenkins. Минус — сервер и агентов придётся поддерживать самостоятельно.
Dagger: пайплайны как код, а не CI-сервис
Dagger — не облачный CI-сервис и не заменяет его. Вы пишете пайплайн в виде кода с помощью Dagger SDK, и один и тот же код работает на ноутбуке и внутри любой CI-системы, включая GitHub Actions. Документация по SDK охватывает Go, Python, TypeScript, Java, PHP и Elixir, а также Dang — собственный скриптовый язык Dagger. Вот та же задача на TypeScript в модуле, созданном командой 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()
}
}
Локально модуль запускается командой dagger call check --source=. --node-version=<your-node-version>. Существующая CI-задача после этого выполняет ту же самую команду — и больше ничего. Если локальный запуск прошёл успешно, в CI выполнятся идентичные шаги в контейнере. Цена — ещё один SDK и движок, которые команде придётся освоить.
Эти команды относятся к Dagger 0.x. В Dagger 1.0, бета-версия которого анонсирована в октябре 2026 года, они переименованы: модуль создаётся командой dagger module init, а dagger call превращается в dagger api call. Сам код на TypeScript остаётся прежним.
Как выбрать альтернативу GitHub Actions?
Правильный выбор зависит от того, где вы хотите выполнять задачи:
- Если нужен полностью облачный CI без какой-либо эксплуатации — используйте CircleCI. Его конфигурация близка к той, что у вас уже есть.
- Если нужна облачная оркестрация на собственных машинах или машинах вендора — используйте Buildkite, особенно если требуются сборки под macOS.
- Если self-hosting обязателен и есть люди для поддержки — используйте Jenkins.
- Если self-hosting обязателен, а нужно что-то компактное — используйте Woodpecker CI.
- Если настоящая проблема — «локально работает, в CI падает» — добавьте Dagger, а в качестве раннера оставьте любой из перечисленных инструментов или сам GitHub Actions.
- Если проблема только во времени ожидания в очереди — сначала попробуйте self-hosted раннеры GitHub Actions.
Docker-бэкенду Woodpecker и Dagger требуется контейнерная среда выполнения. Если Docker Desktop не подходит для ваших машин, Dagger также работает с Podman и nerdctl, а Woodpecker можно запускать в Kubernetes или напрямую на хосте с помощью локального бэкенда.
Какой бы инструмент вы ни выбрали, начните с переноса всей логики сборки в npm-скрипты. Затем испытайте замену на одной ветке параллельно с GitHub Actions и в течение недели сравнивайте результаты, прежде чем окончательно переключиться.
Часто задаваемые вопросы
Взимает ли GitHub поминутную плату за self-hosted раннеры в GitHub Actions?
Нет. GitHub не берёт поминутную плату за использование self-hosted раннеров, поэтому вы платите только за машины, на которых они работают. В декабре 2025 года GitHub объявил о введении платформенного сбора в размере 0,002 доллара США за минуту для self-hosted раннеров с 1 марта 2026 года, но затем отложил его, чтобы пересмотреть подход. Прежде чем строить сравнение затрат на любой из этих цифр, сверьтесь с документацией GitHub по тарификации Actions.
Можно ли запустить задачу CircleCI локально перед пушем?
Да, по одной задаче за раз. CircleCI CLI запускает отдельную задачу внутри Docker на вашей машине с помощью команды circleci local execute. Workflow локально не запускаются, machine executor не поддерживается. Для конфигурации версии 2.1 сначала экспортируйте обработанную конфигурацию командой circleci config process, а затем передайте этот файл в circleci local execute с флагом -c и именем задачи.
Работает ли Woodpecker CI с репозиториями на GitHub?
Да. Woodpecker поддерживает GitHub, включая GitHub Enterprise, а также GitLab, Gitea, Forgejo и Bitbucket Cloud. Вы регистрируете OAuth-приложение на платформе и передаёте его client ID и secret серверу Woodpecker через переменные окружения, например WOODPECKER_GITHUB_CLIENT и WOODPECKER_GITHUB_SECRET. Репозитории остаются на GitHub, Woodpecker отправляет туда статус пайплайнов, а на вашей инфраструктуре работают только сервер и агенты.
Как запустить функцию Dagger из существующего workflow GitHub Actions?
Добавьте после actions/checkout шаг с официальным action dagger/dagger-for-github. Этот action устанавливает Dagger CLI, запускает Dagger Engine на раннере и вызывает вашу функцию. Укажите verb со значением call и передайте те же аргументы, что и при локальном запуске, например check с каталогом исходников и версией Node. Логика пайплайна остаётся в модуле, поэтому при последующем отказе от GitHub Actions изменится только эта тонкая обёртка.