Pipeline Triggers
FerrFlow works with any CI trigger strategy. This page covers the most common patterns, when to use each one, and how they interact with releaseCommitMode.
Push to main
Section titled “Push to main”The simplest setup: run ferrflow release on every push to the default branch. FerrFlow decides whether a release is needed based on the commits since the last tag.
name: Release
on: push: branches: [main]
jobs: release: runs-on: ubuntu-latest # Skip release commits to avoid infinite loops if: "!startsWith(github.event.head_commit.message, 'chore(release):')" permissions: contents: write steps: - uses: actions/checkout@v6 with: fetch-depth: 0 token: ${{ secrets.FERRFLOW_TOKEN }}
- uses: FerrLabs/ferrflow@v2 env: GITHUB_TOKEN: ${{ secrets.FERRFLOW_TOKEN }}When to use: Most projects. Simple, predictable, fully automated.
Trade-offs: Every push to main triggers a workflow run, even if no release is needed. FerrFlow exits early when there are no releasable commits, so the cost is minimal.
Works with: releaseCommitMode: commit (default) or none.
Tag-triggered
Section titled “Tag-triggered”Run your build/deploy pipeline when FerrFlow creates a new tag. This separates the release step (tagging) from the downstream steps (building, publishing, deploying).
name: Build & Publish
on: push: tags: - 'v*' # single-repo: v1.2.0 - '*@v*' # monorepo: api@v1.2.0, site@v0.5.1
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6
- name: Extract version from tag id: version run: | TAG="${GITHUB_REF_NAME}" VERSION="${TAG##*v}" echo "tag=$TAG" >> "$GITHUB_OUTPUT" echo "version=$VERSION" >> "$GITHUB_OUTPUT"
- name: Build run: echo "Building version ${{ steps.version.outputs.version }}"When to use: When you want to decouple versioning from build/deploy. Common for Docker image builds, npm publishing, or binary releases.
Trade-offs: Requires two workflows: one for the release (push-to-main) and one for the downstream build (tag-triggered). Adds a few seconds of latency between the tag push and the build start.
Monorepo: per-package builds
Section titled “Monorepo: per-package builds”In a monorepo, use tag patterns to build only the package that was released:
name: Build Package
on: push: tags: - 'api@v*' - 'site@v*'
jobs: build-api: if: startsWith(github.ref_name, 'api@v') runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - run: echo "Building API ${{ github.ref_name }}"
build-site: if: startsWith(github.ref_name, 'site@v') runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - run: echo "Building site ${{ github.ref_name }}"Release-triggered
Section titled “Release-triggered”Run a pipeline when a GitHub Release is published. This works well with FerrFlow’s --draft flag: FerrFlow creates a draft release, you review it, then publishing triggers the build.
name: Deploy
on: release: types: [published]
jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: ref: ${{ github.event.release.tag_name }}
- name: Deploy run: echo "Deploying ${{ github.event.release.tag_name }}"When to use: When you want a manual review gate before deploying. Create draft releases with ferrflow release --draft, review the changelog, then publish.
Trade-offs: Adds a manual step. The draft release must be published before the deploy runs.
Works with: All releaseCommitMode values.
Manual (workflow_dispatch)
Section titled “Manual (workflow_dispatch)”Trigger a release on demand with an optional dry-run flag. Useful for controlled release cadences or when you don’t want every merge to potentially release.
name: Release
on: workflow_dispatch: inputs: dry_run: description: 'Dry run (no tags, no commits, no releases)' type: boolean default: false
jobs: release: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v6 with: fetch-depth: 0 token: ${{ secrets.FERRFLOW_TOKEN }}
- uses: FerrLabs/ferrflow@v2 with: args: ${{ inputs.dry_run == true && '--dry-run' || '' }} env: GITHUB_TOKEN: ${{ secrets.FERRFLOW_TOKEN }}When to use: Teams that prefer explicit release decisions over automatic releases. Also useful as a secondary workflow alongside push-to-main for ad-hoc releases.
Trade-offs: Requires someone to click “Run workflow” in the Actions tab. Commits can pile up between releases, producing larger changelogs.
PR-based
Section titled “PR-based”Use releaseCommitMode: pr to have FerrFlow open a pull request with the version bump instead of committing directly. The release completes when the PR is merged.
{ "workspace": { "releaseCommitMode": "pr" }}name: Release
on: push: branches: [main]
jobs: release: runs-on: ubuntu-latest if: "!startsWith(github.event.head_commit.message, 'chore(release):')" permissions: contents: write pull-requests: write steps: - uses: actions/checkout@v6 with: fetch-depth: 0 token: ${{ secrets.FERRFLOW_TOKEN }}
- uses: FerrLabs/ferrflow@v2 env: GITHUB_TOKEN: ${{ secrets.FERRFLOW_TOKEN }}When to use: When you want to review version bumps before they land, or when branch protection prevents direct pushes to main.
Trade-offs: Adds an extra merge step. The PR must be merged before tags are created.
Works with: releaseCommitMode: pr only. Requires pull-requests: write permission.
Combining strategies
Section titled “Combining strategies”A common production setup combines push-to-main for versioning with tag-triggered builds:
# Workflow 1: Version and tag on every push to mainname: Releaseon: push: branches: [main]jobs: release: if: "!startsWith(github.event.head_commit.message, 'chore(release):')" runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v6 with: fetch-depth: 0 token: ${{ secrets.FERRFLOW_TOKEN }} - uses: FerrLabs/ferrflow@v2 env: GITHUB_TOKEN: ${{ secrets.FERRFLOW_TOKEN }}# Workflow 2: Build and deploy when a tag is pushedname: Buildon: push: tags: ['v*', '*@v*']jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - run: echo "Building ${{ github.ref_name }}"Summary
Section titled “Summary”| Trigger | Automatic | Review gate | Best for |
|---|---|---|---|
| Push to main | Yes | No | Most projects |
| Tag-triggered | Yes | No | Decoupled build/deploy |
| Release-triggered | No | Yes | Draft → review → publish |
| Manual | No | Yes | Controlled release cadence |
| PR-based | Partial | Yes | Branch protection / review |