Next.js server integration
Record workflows in Route Handlers and Server Actions.
Install
npm i @flowmarkdev/nodeConfigure 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.