Runlane
Get started

Run your first task

Install Runlane, execute one local task, and read its stored result.

In this tutorial, you will create one task, run it in memory, and read its result. The whole example lives in one file.

Before you start

You need Node.js 22.18.0 or newer and an existing TypeScript project. This path uses Node's built-in TypeScript type stripping.

Install Runlane, the local lane, and Zod:

npm install @runlane/core @runlane/lane-local zod

Check that Node meets the package requirement:

node --version

Create the task

Create runlane-quickstart.mts. The .mts extension makes the example an ES module without depending on your project's package.json module setting:

runlane-quickstart.mts
import { createRunlane, queue, task } from '@runlane/core'
import { createLocalLane } from '@runlane/lane-local'
import * as z from 'zod'

const sendWelcomeEmail = task({
  id: 'email.send-welcome',
  output: z.object({ sentTo: z.string() }),
  schema: z.object({ email: z.email() }),
  run: ({ email }) => ({ sentTo: email }),
})

const runlane = createRunlane({
  lane: createLocalLane(),
  queues: [queue({ name: 'default', default: true })],
  tasks: { sendWelcomeEmail },
})

const { run: queuedRun } = await runlane.trigger(runlane.tasks.sendWelcomeEmail, {
  email: 'ada@example.com',
})

await runlane.drain()

const storedRun = await runlane.runs.get(runlane.tasks.sendWelcomeEmail, queuedRun.id)

console.log(
  JSON.stringify({
    queued: queuedRun.status,
    completed: storedRun?.status,
    output: storedRun?.output,
  }),
)

await runlane.close()

The payload schema validates input before Runlane creates the run. The output schema validates the result before success and gives storedRun.output its inferred type.

The named task catalog keeps both types tied to the task registered by the worker.

Run the task

node runlane-quickstart.mts

You should see:

{ "queued": "queued", "completed": "succeeded", "output": { "sentTo": "ada@example.com" } }

trigger() stored a queued run. drain() claimed and executed currently due work, then runs.get() read the materialized result from the lane.

What just happened

The local lane keeps all state in the current process. It is useful for development and tests, but process exit deletes its runs and it cannot share work between separate processes.

If it does not work

If the install reports an unsupported engine, upgrade Node to 22.18.0 or newer. If execution returns no completed run after changing the example, confirm that the runtime has exactly one default queue and that the task is present in its tasks catalog.

Next, add Runlane to your app without duplicating runtime configuration.

On this page