Architecture
Project structure
packages/next-workflow-builder/
└── src/
├── next/ # Next.js plugin configuration
│ ├── index.ts # Plugin entry (nextWorkflowBuilder fn)
│ ├── types.ts # Config types
│ └── schema.ts # Config schema validation (Zod)
│
├── client/ # React components and hooks
│ ├── index.ts # Client exports (WorkflowPage, Layout, etc.)
│ ├── components/
│ │ ├── layout.tsx # Layout wrapper component
│ │ ├── pages/ # WorkflowPage, HomePage, WorkflowsRedirect
│ │ ├── workflow/ # Editor, canvas, nodes, toolbar
│ │ ├── overlays/ # Connection, configuration, settings
│ │ ├── providers/ # LayoutProvider, context providers
│ │ ├── settings/ # Account and integrations manager
│ │ └── ui/ # Radix UI primitives (button, dialog, etc.)
│ ├── hooks/ # Custom React hooks
│ └── lib/
│ ├── api-client.ts # Client-side API helper
│ ├── auth-client.ts # Auth client setup
│ ├── workflow-codegen.ts # Code generation engine
│ ├── workflow-store.ts # Workflow Jotai state
│ ├── ai-gateway/ # AI Gateway configuration
│ └── codegen-templates/ # Code generation templates
│
├── server/ # Server-side code
│ ├── index.ts # Server exports
│ ├── types.ts # Action & integration types
│ ├── constants.ts # Path & config constants
│ ├── auth/
│ │ ├── index.ts # Better Auth instance
│ │ ├── config-store.ts # Auth config management
│ │ └── resolve-user.ts # User resolution utilities
│ ├── db/
│ │ ├── index.ts # Drizzle DB instance
│ │ ├── schema.ts # All database tables & types
│ │ └── integrations.ts # Encryption/decryption
│ ├── api/
│ │ ├── index.ts # Main router (GET, POST, etc. exports)
│ │ ├── workflows.ts # Workflow CRUD & execution handlers
│ │ ├── integrations.ts # Integration CRUD handlers
│ │ ├── api-keys.ts # API key management
│ │ ├── users.ts # User profile endpoints
│ │ ├── auth.ts # Auth passthrough to Better Auth
│ │ └── utils.ts # Helper utilities
│ └── lib/
│ ├── metadata.ts # Workflow metadata generation
│ ├── credential-fetcher.ts
│ ├── workflow-logging.ts
│ ├── workflow-executor.workflow.ts
│ ├── condition-validator.ts
│ ├── utils/ # ID generation, redaction, etc.
│ └── steps/ # Built-in step implementations
│ ├── http-request.ts
│ ├── database-query.ts
│ ├── condition.ts
│ ├── trigger.ts
│ └── step-handler.ts # withStepLogging, StepInput
│
├── plugins/ # Plugin system
│ ├── index.ts # Registry functions (20+ utilities)
│ ├── types.ts # Plugin type definitions
│ ├── discover.ts # Plugin discovery & codegen
│ └── _template/ # Template plugin boilerplate
│
└── scripts/ # CLI tools
├── nwb.ts # CLI entry point
├── discover-plugins.ts # Plugin auto-discovery
├── create-plugin.ts # Plugin scaffolding
└── migrate-prod.ts # Production migrationsConsumer app structure
A typical consumer app using next-workflow-builder:
my-app/
├── app/
│ ├── layout.tsx # Root layout with Layout component
│ ├── [[...slug]]/page.tsx # Catch-all workflow pages
│ └── api/[[...slug]]/route.ts # Catch-all API handler
├── lib/ # (auto-generated by nwb discover-plugins)
│ ├── types/integration.ts
│ ├── step-registry.ts
│ ├── codegen-registry.ts
│ └── output-display-configs.ts
├── plugins/
│ ├── index.ts # (user-managed, scaffolded once)
│ ├── slack/
│ ├── github/
│ └── stripe/
├── next.config.ts
└── drizzle.config.ts # Drizzle ORM config for migrationsPlugin registry
The plugin system is built around a central Map<IntegrationType, IntegrationPlugin> registry.
Registration flow
- Each plugin calls
registerIntegration(plugin)in itsindex.ts - You import each plugin in the user-managed
plugins/index.ts(local imports or npm packages) - The
nwb discover-pluginsscript importsplugins/index.tsto populate the registry - Generated files provide the glue between the registry and the runtime:
- Step registry maps
actionId -> () => import("plugin/steps/action") - Type union ensures type safety for integration slugs
- Display configs and codegen templates are registered at import time
- Step registry maps
Virtual module resolution
The Next.js plugin sets up virtual module aliases so the package can import consumer-side files:
virtual:workflow-builder-plugins→ resolves to./plugins/index.tsvirtual:workflow-builder-step-registry→ resolves to./lib/step-registry.ts
These aliases are configured for both Turbopack (resolveAlias) and webpack (resolve.alias).
API routing
The API handler uses a segment-based router instead of Next.js file-based routing. All API requests go through a single
app/api/[[...slug]]/route.ts catch-all handler that re-exports HTTP method handlers from next-workflow-builder/api.
The router matches URL path segments to handlers:
const segments = extractPath(request);
const [s0, s1, s2, s3] = segments;
if (s0 === "workflows") {
if (s1 === undefined && method === "GET") return handleGetWorkflows(request);
// ...
}The router supports:
- Exact segments (
/workflows/create) - Dynamic segments (
/workflows/[workflowId]) - Catch-all segments (
/auth/*)
State management
Client-side state is managed with Jotai :
- Workflow store (
workflow-store.ts) - Nodes, edges, and workflow metadata atoms - Additional state - UI state, auth, integrations
The Layout component wraps the app in a Jotai Provider to make atoms available throughout the component tree.
Code generation
The workflow codegen system converts a visual workflow into standalone TypeScript code:
- Reads the workflow’s nodes and edges
- Resolves each action node’s codegen template from the registry
- Generates a complete file with imports, step functions, and execution flow
- Available as a download (ZIP) or in-editor code view
Templates can be:
- Auto-generated from step files that export
_exportCore - Custom templates defined in the plugin’s
codegenTemplatefield - Registered via the consumer’s
lib/codegen-registry.ts
Technology stack
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| UI | React 19, Radix UI, Tailwind CSS |
| Canvas | React Flow (@xyflow/react) |
| State | Jotai |
| Database | PostgreSQL + Drizzle ORM |
| Auth | Better Auth |
| AI | Vercel AI SDK |
| Animations | Motion (Framer Motion) |
| Validation | Zod |
| Build | TypeScript, Turborepo |