Skip to content
RELKIT
Esc
↑↓navigate↵open⌘Jpreview
On this page

Trigger.dev

Configure Trigger.dev for an Orders CSV task and check worker publication.

Trigger.dev needs a project, environment API key, and published worker generation alongside the RELKIT job binding. This page shows the RELKIT side and the exact registration checks; it is a compatibility guide, not a passing setup tutorial. For a verified local run today, use Inngest or Effect MQ.

Configure an existing app

The --jobs trigger-docker creation tuple is currently rejected before staging because its native and timing evidence is incomplete. Begin with an existing project and install the selected adapter, native SDK and Docker materializer before applying the configuration below:

From this guide’s application/package root, install only its selected requirements:

bun add @relkit/docker@0.7.12 @relkit/local@0.7.12 @relkit/trigger@0.8.1 @trigger.dev/sdk@4.7.2

Keep these owner-specific versions and the lockfile together. Runtime SDKs belong in dependencies; build/type tooling belongs in devDependencies. Installing an adapter does not supply its optional SDK peers or enable the feature’s configuration.

This aligns declarations with the adapter’s current SDK contract. It does not repair the unresolved provider/server compatibility or publish a worker.

jobs.default connects the provider; defaults.jobs selects it. Extend the existing config while retaining its own ID and server settings.

/** Declares task application defaults with inspection disabled until selected. */
import { defineApp } from "@relkit/app/config";
import env from "@app/platform/env.js";
import { docker } from "@relkit/docker";
import { trigger } from "@relkit/trigger";

export default defineApp({
  id: "relkit-trigger",
  env,
  server: { port: 3000, maxBodyBytes: 1_048_576 },
  telemetry: { redaction: { mode: "development-redacted", maxBytes: 65_536 } },
  jobs: { default: docker(trigger()) },
  defaults: { jobs: "default" },
});

What provider setup is missing

Trigger’s official Docker Compose setup runs a webapp, database, Redis, and worker supervisor. After bringing that stack up, an operator creates a project, obtains a development environment API key, configures the SDK base URL and key, and deploys a worker containing the task before triggering a run. These are provider-side steps; the RELKIT binding above does not replace them. The generated trigger-docker recipe instead starts a pinned webapp image with PostgreSQL and a RELKIT worker, generates a random projectRef and secretKey, and passes them to the SDK. It does not create those credentials in Trigger.dev or publish a worker generation. Its pinned webapp also fails its current environment and port configuration. Running the official Compose stack separately does not make this generated RELKIT profile compatible by itself. The adapter currently imports @trigger.dev/sdk/v3; Trigger’s self-hosting guidance says 4.5.0 is the last server release supporting v3 tasks. The server, SDK, task publication, and project credentials must be aligned together. Do not paste a production Trigger key into the generated source or assume that local up completing means a task is registered there.

Add the Orders boundary

These instructions extend an existing application; they do not create a jobs starter. For a grouped minimal app, create src/services/orders/functions, tasks and jobs. Add the following boundary and health function. In a compatible flat app, use its existing src/orders/ root consistently instead. If Orders already exists, extend its public functions rather than replacing the boundary.

/** Declares the orders service boundary and its public members. */
import { defineService } from "@relkit/app/services";
import exportOrders from "@app/services/orders/jobs/export-orders.job.js";
import exportOrdersTask from "@app/services/orders/tasks/export-orders.task.js";
import health from "@app/services/orders/functions/health.function.js";

export default defineService({
  functions: { health },
  tasks: { exportOrdersTask },
  jobs: { exportOrders },
});
/** Supplies the orders service with a validated health result independent of job execution. */
import { defineFunction } from "@relkit/app/functions";
import { z } from "@relkit/app/schema";

export default defineFunction({
  id: "orders.health",
  input: z.object({}),
  output: z.object({ ok: z.literal(true) }),
  handler: async () => ({ ok: true as const }),
});

Add src/services/orders/jobs/export-orders.job.ts from the maintained task fixture:

/** Registers the export task as a public job exposing trigger, lookup, list and watch with progress/output fields. */
import { defineJob } from "@relkit/app/jobs";
import exportOrders from "@app/services/orders/tasks/export-orders.task.js";

const exportOrdersJob = defineJob({
  id: "orders.export-orders-job",
  name: "exportOrders",
  task: exportOrders,
  client: {
    public: true,
    operations: ["trigger", "get", "list", "watch"],
    fields: ["status", "progress", "output"],
  },
});

export default exportOrdersJob;

For this provider, set that job’s client.operations to ["trigger"] before checking.

The task file below supplies the job’s imported target. Create the sample input file when absent. Keep existing durable task/job IDs and bump the task version when changing an already deployed contract.

Read the task before running it

Add or update src/services/orders/tasks/export-orders.task.ts with this task. It validates order lines and computes CSV text and a total in cents. The durable declaration does not by itself prove checkpoint or resume support. The sample IDs and SKUs contain no commas or newlines; escape fields for arbitrary text. This new app keeps task version 1. The explicit job exposes exportOrders; keep one job with this public name.

import { defineTask } from "@relkit/app/tasks";
import { z } from "@relkit/app/schema";

const order = z.object({
  id: z.string().min(1),
  sku: z.string().min(1),
  quantity: z.number().int().positive(),
  unitPriceCents: z.number().int().nonnegative(),
});

const exportOrders = defineTask({
  id: "orders.export-orders",
  version: "1",
  execution: "durable",
  input: z.object({ orders: z.array(order) }),
  output: z.object({ csv: z.string(), orderCount: z.number().int(), totalCents: z.number().int() }),
  handler: async ({ orders }, context) => {
    const lines = ["order_id,sku,quantity,total_cents"];
    let totalCents = 0;
    for (const item of orders) {
      const lineTotal = item.quantity * item.unitPriceCents;
      totalCents += lineTotal;
      lines.push([item.id, item.sku, item.quantity, lineTotal].join(","));
    }
    context.log.info("Orders CSV prepared", { orderCount: orders.length, totalCents });
    return { csv: lines.join("\n") + "\n", orderCount: orders.length, totalCents };
  },
});

export default exportOrders;

Create or update examples/export-orders.json with these two rows. A completed task should return orderCount: 2, totalCents: 2100, and CSV line totals 900 and 1200.

{
  "orders": [
    { "id": "order-1", "sku": "tea", "quantity": 2, "unitPriceCents": 450 },
    { "id": "order-2", "sku": "mug", "quantity": 1, "unitPriceCents": 1200 }
  ]
}

Check the local profile before submitting

The task source can pass RELKIT checks, but these commands are a diagnostic gate. If local status reports an unhealthy provider, stop here; a RELKIT jobs list result only proves that the compiler discovered the job, not that Trigger.dev registered it.

bun run check
bun run typecheck
bun run relkit local up --detach
bun run relkit local status
docker ps --filter name=service-trigger --format '{{.Names}} {{.Status}} {{.Ports}}'

If the Trigger container exits, stop here and inspect its logs. If a future compatibility fix makes the provider and worker ready, start bun run dev, then use jobs list to confirm RELKIT discovered exportOrders, then submit the input. An accepted receipt is only an enqueueing signal. Require all three before claiming the integration works: the task appears in Trigger.dev’s project dashboard, its native run reaches COMPLETED, and the run output includes orderCount: 2 and totalCents: 2100.

bun run relkit jobs capabilities
bun run relkit --json jobs list
bun run relkit --json jobs trigger --job exportOrders --input-file examples/export-orders.json --operation-id orders-csv-1
bun run relkit jobs runs get --run-id <runId>

Replace <runId> with the accepted handle only if submission succeeds. Compare it with the native Trigger.dev run ID and worker logs. No screenshot of a completed native run is shown here because this profile did not reach that state in a fresh app. A screenshot of jobs list, an accepted receipt, or a healthy Docker container would not prove that the task was published and executed.

Current verification limit: The local-source task passes check and typecheck, but the pinned Trigger image requires service environment variables absent from the current recipe and listens on a different port. Once the image was cached, local up briefly reported healthy while the Trigger container exited. Adding the SDK manually allowed the RELKIT backend to start during a diagnostic run, but submission returned an unknown outcome and the worker never became ready. We therefore have no proof that this task was registered with Trigger.dev or executed there. This provider’s runtime compatibility remains unverified in the capability evidence. Do not rely on checkpoint resume, durable sleep, observation, or cancellation until the selected environment reports and demonstrates them. Keep worker publication and definition registration staged so an unsuccessful replacement does not remove the active worker generation. Continue with provider comparison to choose a profile by verified capability.