Onboarding
Add an onboarding process after registration to collect more data on your new users and to perform specific actions.
The onboarding process is built on the top of the Quick Form component that use Stepper under the hood.
Redirection
After registration, the user is redirected to the /dashboard endpoint. You are using the /dashboard/layout.tsx file to redirect the user to the onboarding page if the user is not onboarded.
// imports ... export default async function OrganizationsLayout( props: React.PropsWithChildren, ): Promise<React.JSX.Element> { const db = await getDBClient(); const user = await db.user.get(); if (!user) { return redirect(dashboardRoutes.paths.auth.signIn); } if (!user.completedOnboarding) { // Redirect to the onboarding page return redirect(dashboardRoutes.paths.onboarding.index); } return <UserProvider user={user}>{props.children}</UserProvider>; }
We are using an completedOnboarding column in the user table to check if the user has completed the onboarding process.
This simple procedure allows us to make sure that all users are onboarded before accessing the dashboard.
Config object
To update the onboarding flow, you have to edit the apps/dashboard/config/onboarding.config.ts file :
import { LogicInputConfig, QuickFormInputConfig, QuickFormStepConfig, QuickFormUIComponent, QuickFormWrapperConfig, } from "@kit/utils/quick-form"; import { z } from "zod"; import { AvatarPlaceholder } from "~/components/avatar-placeholder"; export const onboardingUserSchema = { userImageUrl: z .string({ invalid_type_error: "Image must be a string.", }) .optional() .nullable(), userName: z .string({ required_error: "Name is required.", invalid_type_error: "Name must be a string.", }) .trim() .min(1, "Name is required.") .max(64, "Maximum 64 characters allowed."), userPhone: z .string({ invalid_type_error: "Phone must be a string.", }) .trim() .max(16, "Maximum 16 characters allowed.") .optional() .or(z.literal("")), userEmail: z.string().email("Please enter a valid email"), }; export const onboardingSchema = { ...onboardingUserSchema, userRole: z.enum([ "designer", "programmer", "product_manager", "tester", "marketer", ]), }; type OnboardingSchema = typeof onboardingSchema; export const settingsForUserCreation: ( | QuickFormUIComponent | QuickFormInputConfig<typeof onboardingUserSchema> | QuickFormWrapperConfig<typeof onboardingUserSchema> | LogicInputConfig<typeof onboardingUserSchema> )[] = [ { type: "user_media", slug: "userImageUrl", className: "mx-auto", triggerClassName: "size-32 rounded-full mx-auto", imageClassName: "w-full h-full object-cover", placeholder: <AvatarPlaceholder className="size-full text-4xl" />, }, { type: "text", slug: "userName", label: "Name", }, { type: "phone", slug: "userPhone", label: "Phone", }, { type: "text", slug: "userEmail", label: "Email", disabled: true, }, ]; export const onboardingStepsConfig: QuickFormStepConfig<OnboardingSchema>[] = [ { type: "step", label: "User", header: ( <> <h1 className="text-xl leading-none font-semibold tracking-tight lg:text-2xl"> Set up your profile </h1> <p className="text-muted-foreground text-sm lg:text-base"> Make sure your profile information is correct. You'll be able to change this later. </p> </> ), settings: settingsForUserCreation, }, { type: "step", label: "Profession", settings: [ { type: "question_select", slug: "userRole", question: "Who are you ?", questionDescription: "Help us understand your role to personalize your experience.", answers: [ { value: "designer", label: "Designer", icon: "Sparkles", description: "Create beautiful and intuitive user interfaces and experiences.", }, { value: "programmer", label: "Programmer", icon: "Code", description: "Build robust software solutions and develop cutting-edge applications.", }, { value: "product_manager", label: "Product manager", icon: "ShoppingCart", description: "Strategize product vision, roadmap planning, and feature development.", }, { value: "tester", label: "Tester", icon: "TestTubeDiagonal", description: "Ensure quality through comprehensive testing and bug identification.", }, { value: "marketer", label: "Marketer", icon: "Store", description: "Drive growth through strategic marketing campaigns and user acquisition.", }, ], }, ], }, ];
Premade templates for emails to make your brand more professional.
Add subscription and payment capabilities to your application with multiple billing providers.
How is this guide?
Last updated on 2/27/2026