SDK reference

Next.js server integration

Record workflows in Route Handlers and Server Actions.

Install

npm i @flowmarkdev/node

Configure a server client

Use the @flowmarkdev/node/next entry point from a server-only module. This is an ordinary module; neither the module name nor flowmark.config.ts is automatically discovered.

// lib/flowmark.ts
import { createFlowmark } from "@flowmarkdev/node/next"

export const flowmark = createFlowmark()

Set the private FLOWMARK_API_KEY in the server environment. Set FLOWMARK_API_URL when the API is not the development default http://localhost:3003. Never put a private write key in client code or a NEXT_PUBLIC_* variable.

Instrument a handler

Use the shared client in a Route Handler or Server Action. importInvoices below belongs to your application:

import { flowmark } from "@/lib/flowmark"

export async function POST() {
  const flow = flowmark.workflow("invoice.import")
  try {
    flow.step("file-validated", {
      properties: { rowCount: 120 },
    })
    const result = await importInvoices()
    flow.done({ result: { saved: result.saved, skipped: result.skipped } })
  } catch (cause) {
    flow.error({
      code: "INVOICE_IMPORT_FAILED",
      handled: false,
      retryable: false,
    })
    flow.fail({ code: "INVOICE_IMPORT_FAILED", retryable: false })
    throw cause
  }
  return Response.json({ accepted: true })
}

Automatic delivery

The adapter uses Next.js after() to drain delivery after the response; there is no need for a transport, wrapper, or manual flush. Use it only in supported server request contexts—not Client Components, middleware, or during rendering. If telemetry delivery fails, the adapter logs it and does not undo application changes.

defineConfig() can provide typed server options, but it only returns its input unchanged. Explicitly import and pass the configuration to the client; no configuration file is loaded automatically.

See local development for the current stack and configuration for all client options.

Request lifecycle

Create the shared adapter in a server-only module, then start runs inside a supported request context. The adapter returns only workflow(); it does not expose manual flush() or shutdown().

Each call to workflow() creates a separate delivery client for that request lifecycle. No React provider, callback wrapper, or special configuration file is needed.

Continue instrumenting

The returned run has the standard marker API: checkpoints, operations, progress, errors, properties, and completion. Use operation() for measured work and done({ result }) for a bounded business summary.

On this page