Skip to content

Documentation: Workflow discovery mechanism and "use server" incompatibility #817

@pksorensen

Description

@pksorensen

GitHub Issue for Vercel Workflow Repository

Copy the content below and submit it to: https://github.com/vercel/workflow/issues


Title

Documentation: Workflow discovery mechanism and "use server" incompatibility

Labels

  • documentation
  • question

Description

Summary

After integrating Vercel Workflows v4.0.1-beta.49 with Next.js 16.1.4, we discovered two important behaviors that should be documented:

  1. Workflow discovery mechanism is not clearly explained in the documentation
  2. "use server" directive is incompatible with the workflow bundler

Issue #1: Workflow Discovery Mechanism

Current documentation gap:
The documentation doesn't clearly explain how workflows are discovered during the build process. It shows examples using dedicated API routes (/api/workflows/route.ts), but doesn't explain the underlying discovery mechanism.

What we discovered:
By analyzing the source code (packages/next/src/index.ts and builder.ts), we found that the bundler:

  1. Scans specific directories: pages/, app/, src/pages/, src/app/
  2. Looks for specific file types: route.ts, page.ts, layout.ts
  3. Follows start() calls from workflow/api to discover workflows
  4. The code never executes - it's purely for build-time analysis

Suggested improvement:
This means workflows can be discovered from existing layout.tsx files instead of creating dedicated routes:

// app/layout.tsx
import { start } from "workflow/api";
import { myWorkflow } from "@/workflows/my-workflow";

// Workflow discovery (never executes, only for bundler)
const _workflowDiscovery = {
  my: () => start(myWorkflow, []),
};

export default function RootLayout({ children }) {
  return children;
}

This is cleaner than creating extra routes solely for discovery. Suggest documenting this pattern.


Issue #2: "use server" Incompatibility

Problem:
Next.js Server Actions use "use server" to mark server-only modules. However, this directive causes build errors when files are imported by workflows (even via dynamic imports in step functions).

Error:

Server Actions must be async functions.

./src/app/.well-known/workflow/v1/step/route.js:6292:3
Ecmascript file had an error
  6292 |   "src/lib/storage/calendar-references.ts"() {
  6293 |     "use strict";
  6294 |     "use server";  // ← Error here

Root cause:
The workflow bundler wraps modules in synchronous initialization functions:

var init_module = __esm({
  "src/lib/storage/my-file.ts"() {  // ← Synchronous function
    "use strict";
    "use server";  // ← Next.js: "This must be in async context!"
    // ...
  }
});

Next.js validates that "use server" appears only in async function contexts. The bundler's synchronous module wrapper violates this constraint.

This happens even when:

  • All exported functions are async
  • The file is imported via dynamic await import() in a step function
  • The workflow correctly uses "use workflow" and "use step" directives

Workaround:
Remove "use server" from files imported by workflows:

// ✅ WORKS - No "use server", still server-only via Node.js APIs
import fs from "fs/promises";

export async function getUserData(userId: string) {
  // Uses fs - server-only by nature
}
// ❌ FAILS - Has "use server", causes bundler error
"use server";

export async function getUserData(userId: string) {
  // ...
}

Keep "use server" only in true Server Actions (form actions called from client components) that workflows don't import.

Suggested improvements:

  1. Document this incompatibility in the Next.js integration guide
  2. Explain the workaround - separate business logic (no "use server") from Server Actions (with "use server")
  3. Consider adding a warning when the bundler detects "use server" in bundled files
  4. Long-term: Investigate if the bundler could use async module wrappers or handle this differently

Environment

  • Vercel Workflows: v4.0.1-beta.49
  • Next.js: 16.1.4
  • Node.js: v22.x
  • Package manager: npm

Example Repository

We can provide a minimal reproduction if helpful.

Proposed Documentation Updates

  1. Add section on workflow discovery:

    • Explain the build-time scanning mechanism
    • Show that layout.tsx, page.tsx, route.ts can all be used
    • Document that start() calls are for discovery only (never execute)
  2. Add section on Next.js Server Actions compatibility:

    • Document "use server" incompatibility
    • Explain the synchronous wrapper constraint
    • Provide recommended code organization pattern
    • Show how to separate business logic from Server Actions
  3. Add to troubleshooting guide:

    • Common error: "Server Actions must be async functions"
    • Solution: Remove "use server" from workflow-imported files

Additional Context

We successfully integrated workflows into a large Next.js app after discovering these patterns. Having this documented would save others significant debugging time.

Thank you for this excellent framework! These are just documentation gaps we encountered during integration.

--

A personal touch, we used cron to schedule workflows and place this in our instructions.ts files to wire it up. but it did not detect our workflows this way which caused all this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions