Pipelines and triggers

Define what starts a pipeline, which jobs it calls, and how runs are limited.

Inngest CI is an Inngest Labs project: early, moving fast, and shaped by your feedback. What's Labs?

A pipeline is one Inngest function. Its handler is plain TypeScript that calls jobs, so it can branch, loop, and run jobs in parallel. Inngest starts a run when one of its triggers fires.

Define a pipeline

ci/pipelines.ts
import { github } from "@inngest/ci";
import { ci } from "./client";

export const pr = ci.pipeline(
  {
    id: "pr",
    on: github.pullRequest(),
  },
  async () => {
    await Promise.all([lint(), test()]);
  },
);

The id names the function, the run, and the check. The handler receives event, events, runId, pipelineId, repo, attempt, and logger. Serve pipelines with ci.functions(), as the quick start shows.

Triggers

A trigger starts a pipeline and types its event. Pass an array to use several.

TypeScript
export const merged = ci.pipeline(
  {
    id: "merged",
    on: github.pullRequest({ types: ["closed"] }),
  },
  async ({ event }) => {
    if (event.data.pull_request.merged === false) {
      return ci.skip("closed without merging");
    }

    await release();
  },
);
  • github.pullRequest() and github.push() cover pull requests and commits.
  • github.comment() runs on a comment such as /deploy, and github.mergeGroup() runs for the merge queue.
  • { cron } runs on a schedule, and ci.manual() runs on an event you send.

Reference lists every trigger and its options.

Skip a run

Return ci.skip(reason) to end a run early. The check completes as success with the reason, so a required check never waits. changed() reads the changed files before any machine starts:

TypeScript
const touched = await changed("src/**", "package.json");

if (touched === false) {
  return ci.skip("nothing that affects the build changed");
}

When changed() cannot tell what changed, it returns true so nothing is skipped by mistake. That happens when the run has no repository or no GitHub credentials, when it has no pull request or push range (a cron, a manual run, a merge group, or a push that creates a branch), when a local run cannot find its base branch, and when a compare hits GitHub's 300-file cap.

Flow control

Pipeline options accept every Inngest flow control setting. To cancel a run when a newer one starts for the same pull request, use singleton:

TypeScript
export const pr = ci.pipeline(
  {
    id: "pr",
    on: github.pullRequest(),
    singleton: { key: "event.data.pull_request.number", mode: "cancel" },
    concurrency: {
      key: "event.data.repository.owner.login",
      limit: 20,
      scope: "account",
    },
  },
  async () => {
    await test();
  },
);

Use concurrency to cap how many pipelines run at once. throttle, rateLimit, debounce, and priority work too.

Next steps