Jobs
Split a pipeline into units of work that each run on their own machine and report their own check.
Inngest CI is an Inngest Labs project: early, moving fast, and shaped by your feedback. What's Labs?
A job is a function you define with ci.job() and call from a pipeline or another job. Each job gets its own machine and its own check on GitHub.
Define and call a job
const test = ci.job("test", async () => {
await checkout();
await $`pnpm test`;
});
const build = ci.job({ id: "build", machine: { vcpu: 4 } }, async () => {
await checkout();
await $`pnpm build`;
});
- A job has no return value. Call it for its commands and its check.
- Each call runs the job again, on a new machine with its own check. A second call to
testshows astest (2). To share one build between jobs, usefrom(). - The machine starts on the job's first command. A job with no commands never gets one.
- When a command fails, the job's check fails and the pipeline ends.
Run jobs in sequence with await, or in parallel with Promise.all:
await Promise.all([lint(), test()]);
await deploy();
Jobs never share a machine. To build on another job's work, use from().
Run a job for every combination
ci.matrix runs a job for every combination of its axes. Each combination is its own job, with its own machine and check.
const compat = ci.matrix(
{
id: "compat",
axes: { node: ["20", "22", "24"], db: ["sqlite", "postgres"] },
exclude: [{ node: "20", db: "postgres" }],
concurrency: 3,
},
async ({ node, db }) => {
await from(base);
await $`npx -y node@${node} --test`.env({ TEST_DATABASE: db });
},
);
Call compat() to run every combination, or compat({ node: "22" }) to run only the matching ones. Reference covers include, failFast, and per-combination options.
Use Inngest steps in a job
A job is an Inngest function body, so the step API works inside it. Wrap side effects in step.run, because code outside a command can run again when the run resumes.
import { step } from "inngest";
const migrations = ci.job("migrations", async () => {
const db = await step.run("create-db-branch", async () => {
return neon.branches.create({ parent: "main" });
});
await checkout();
await $`pnpm db:migrate`.env({ DATABASE_URL: db.url });
});
step.waitForEvent, step.sleep, and step.invoke work too, and a wait holds no worker.