Building Workflows
How to define multi-step workflows with the flow builder.
A workflow is a sequence of steps, where each step is usually a Rilaykit form. The workflow builder allows you to chain these steps together and configure the navigation logic between them.
The flow Builder
The flow class provides a static factory method to build multi-step workflows. It follows the same builder pattern as forms, with method chaining and full type safety.
1. Create your Form Configurations
First, you need a formConfig for each step of your workflow. You'll create these using the standard form builder.
import { rilay } from '@/lib/rilay';
const personalInfoForm = rilay.form('personal-info').add(...).build();
const preferencesForm = rilay.form('preferences').add(...).build();
const reviewForm = rilay.form('review').add(...).build();You can also pass a form builder instance directly to a step. It will be built automatically.
2. Start the Flow Builder
Use .flow() on your rilay instance to begin building your workflow. The workflow ID and name are optional — if not provided, they will be auto-generated.
import { rilay } from '@/lib/rilay';
// With explicit ID and name (recommended for production)
const workflowBuilder = rilay.flow(
'user-onboarding',
'User Onboarding Workflow',
'A multi-step workflow to onboard new users' // Optional description
)
// With auto-generated ID and default name (useful for prototyping)
const quickWorkflow = rilay.flow()3. Add Steps
Use .step() to add steps to your workflow. You must provide at least a title and formConfig.
//...
.step({
id: 'personal-info',
title: 'Personal Information',
description: 'Tell us about yourself',
formConfig: personalInfoForm,
})
.step({
id: 'preferences',
title: 'Preferences',
description: 'Set your preferences',
formConfig: preferencesForm,
allowSkip: true, // This step is optional
})
.step({
id: 'review',
title: 'Review & Feedback',
description: 'Review your information',
formConfig: reviewForm,
})
// ...4. Configure Navigation and Hooks
You can configure the overall workflow behavior with the unified .configure() method.
// ...
.configure({
analytics: {
onWorkflowStart: (workflowId) => console.log(`Workflow ${workflowId} started.`),
onStepComplete: (stepId, duration) => console.log(`Step ${stepId} took ${duration}ms.`),
}
})
// ...5. Build the Configuration
Finally, call .build() to get the final workflowConfig object.
const workflowConfig = rilay.flow(...)
.step(...)
.step(...)
.configure(...)
.build();This configuration can now be passed to the <Workflow> component, which will build it automatically if you pass the builder instance.
When to use .build()
Just like with forms, you often don't need to call .build() on a workflow builder. The <Workflow /> component handles it for you.
You should call .build() manually when you need the final, serializable WorkflowConfig object, for example, to save it as JSON or for debugging.
Step Configuration
The object passed to .step() has several options:
id(optional): A unique identifier for the step. Auto-generated if not provided.title(required): A human-readable title for the step, often shown in the stepper.description(optional): A short description of the step.formConfig(required): The form configuration or form builder instance for this step.renderer(optional): A custom renderer for the body of this specific step.allowSkip(optional, default:false): Iftrue, users can skip this step via<WorkflowSkipButton>.metadata(optional): Structured metadata object withicon,category,tags, and custom fields.conditions(optional): Conditional behavior configuration (visibility, skippable state).after(recommended): Simplified callback with single parameter containing step data and helpers. See Advanced Workflows.onAfterValidation(deprecated): Legacy 3-parameter callback. Useafterinstead for better DX.
Complete Example: User Onboarding Workflow
Let's put it all together. Here is a full example of a 3-step user onboarding workflow.
First, we define the forms for each step:
// 1. Define the forms for each step
const accountForm = rilay.form('account-form')
.add(
{ id: 'email', type: 'email', props: { label: 'Email' }, validation: { validate: [required(), email()] } },
{ id: 'password', type: 'password', props: { label: 'Password' }, validation: { validate: [required(), minLength(8)] } }
);
const profileForm = rilay.form('profile-form')
.add(
{ id: 'firstName', type: 'text', props: { label: 'First Name' } },
{ id: 'lastName', type: 'text', props: { label: 'Last Name' } }
);
const confirmationForm = rilay.form('confirmation-form')
.add({
id: 'terms',
type: 'checkbox', // Assumes a 'checkbox' component is registered
props: {
label: 'I agree to the terms and conditions',
},
validation: {
validate: [
custom(value => value === true, 'You must accept the terms')
]
}
});About Validation
This example uses several built-in validators. To learn more about how validation works in Rilay, check out our in-depth Field and Form Validation guide.
Now, we use the flow builder to chain them together into a workflow:
// 2. Build the workflow
export const onboardingWorkflow = rilay.flow(
'onboarding',
'New User Onboarding'
)
.step({
id: 'account-creation',
title: 'Create Account',
formConfig: accountForm,
metadata: { icon: 'user', category: 'account' },
after: async (step) => {
// Simplified callback signature
console.log('Account created:', step.data.email);
// Pre-fill next step with user's email
step.next.prefill({
email: step.data.email
});
}
})
.step({
id: 'personal-info',
title: 'Your Profile',
formConfig: profileForm,
metadata: { icon: 'profile', category: 'profile' }
})
.step({
id: 'confirmation',
title: 'Confirmation',
formConfig: confirmationForm,
metadata: { icon: 'check', category: 'confirmation' }
})
.configure({
analytics: {
onWorkflowStart: (id) => console.log(`Started: ${id}`),
onWorkflowComplete: (id, totalTime) => console.log(`Completed: ${id} in ${totalTime}ms`),
},
});New in v0.2: The simplified after callback replaces the verbose onAfterValidation (still supported but deprecated).
This onboardingWorkflow builder instance is ready to be passed to the <Workflow /> component, providing a complete multi-step form experience out of the box.