LogoBoring Template

Onboarding Flow

Guide users through setting up their account in a structured, step-by-step process.

The onboarding process guides new users through setting up their account in three main steps: profile setup, workspace creation, and team collaboration.

Process Overview

The onboarding process follows this sequence:

User Authentication

🔑 User signs in with their credentials

Profile Setup

👤 Complete personal profile information

Workspace Creation

🏢 Set up organization workspace and preferences

Team Collaboration

👥 Invite team members and configure permissions

Implementation Details

Onboarding Status Tracking

The system tracks onboarding progress using two main fields in the user settings:

server/db/schemas/user.ts
{
  onboardingStatus: "pending" | "completed";
  onboardingStep: "profile" | "workspace" | "collaborate";
}

These status fields allow the application to remember where users left off and guide them through the remaining steps.

Flow Control

The onboarding flow includes automatic redirects based on the user's progress:

  • Users must be authenticated to access onboarding
  • Completed users are redirected to the main application
  • Users are directed to their last incomplete step

Onboarding Steps

1. Profile Setup

Initial user profile configuration including name, avatar, and preferences.

app/onboarding/profile/page.tsx
export default function ProfileSetup() {
  // Profile setup form and logic
  return (
    <div>
      <h1>Setup your profile</h1>
      <ProfileForm onSubmit={handleSubmit} />
    </div>
  );
}

2. Workspace Setup

Creating and configuring workspace settings, branding, and defaults.

app/onboarding/workspace/page.tsx
export default function WorkspaceSetup() {
  // Workspace setup form and logic
  return (
    <div>
      <h1>Create your workspace</h1>
      <WorkspaceForm onSubmit={handleSubmit} />
    </div>
  );
}

3. Team Collaboration

Inviting team members and setting up roles and permissions.

app/onboarding/collaborate/page.tsx
export default function TeamCollaboration() {
  // Team collaboration form and logic
  return (
    <div>
      <h1>Invite your team</h1>
      <CollaborationForm onSubmit={handleSubmit} />
    </div>
  );
}

Route Structure

Directory Structure

The onboarding flow is implemented using a dedicated route structure in the Next.js app directory.

app/
  onboarding/
    (index)/
      page.tsx      # Main onboarding controller
    profile/        # Step 1: Profile setup
    workspace/      # Step 2: Workspace setup
    collaborate/    # Step 3: Team collaboration

Usage Example

To check the user's onboarding status:

Example Query
const [settings] = await db
  .select({
    onboardingStatus: userSettings.onboardingStatus,
    onboardingStep: userSettings.onboardingStep,
  })
  .from(userSettings)
  .where(eq(userSettings.userId, user.id))
  .limit(1);

Best Practices

User Experience

  • Keep steps simple and focused
  • Provide clear progress indicators
  • Allow users to save progress and continue later
  • Validate input in real-time

Implementation

  • Store onboarding state in the database
  • Implement proper redirects for incomplete steps
  • Handle edge cases like skipped steps
  • Provide a way to reset onboarding if needed

Customization

The onboarding flow can be customized to fit your specific application needs by modifying the steps, forms, and validation logic.

You can modify the onboarding flow by:

  1. Adding or removing steps in the process
  2. Customizing the forms and validation rules
  3. Changing the redirect logic based on user roles or other criteria
  4. Adding additional status tracking fields

Complete Implementation Example

Here's a more complete example of the onboarding controller:

app/onboarding/(index)/page.tsx
import { redirect } from "next/navigation";
import { db } from "@/server/db/config/database";
import { userSettings } from "@/server/db/schemas";
import { eq } from "drizzle-orm";
import { auth } from "@/lib/auth";
 
export default async function OnboardingController() {
  const session = await auth();
 
  if (!session) {
    redirect("/sign-in");
  }
 
  const user = session.user;
 
  const [settings] = await db
    .select({
      onboardingStatus: userSettings.onboardingStatus,
      onboardingStep: userSettings.onboardingStep,
    })
    .from(userSettings)
    .where(eq(userSettings.userId, user.id))
    .limit(1);
 
  if (settings?.onboardingStatus === "completed") {
    redirect("/dashboard");
  }
 
  switch (settings?.onboardingStep) {
    case "profile":
      redirect("/onboarding/profile");
    case "workspace":
      redirect("/onboarding/workspace");
    case "collaborate":
      redirect("/onboarding/collaborate");
    default:
      redirect("/onboarding/profile");
  }
}

On this page