# Sign Up

> User registration with email verification, personal account creation, and optional terms acceptance.

*Canonical: https://makerkit.dev/docs/nextjs-drizzle/authentication/sign-up*

---

{% sequence title="Sign Up Flow" description="What happens when a user registers." %}

[User submits registration form](#registration-form)

[Email verification sent](#email-verification)

[Personal account created](#account-creation)

[User redirected to dashboard](#post-registration)

{% /sequence %}

New users register through the sign up page, which creates a user record and a personal account. Email verification is required by default.

**Page location:** `apps/web/app/[locale]/auth/sign-up/page.tsx`
**Route:** `/auth/sign-up`

## Registration Form

The sign up form collects name, email, and password.

{% img src="/images/docs/sign-up-email-password.webp" width="2388" height="1798" alt="User registration form showing name, email, and password fields with a create account button" /%}

### Configuration

```bash {% title="apps/web/.env.local" %}
# Enable email/password registration (default: true)
NEXT_PUBLIC_AUTH_PASSWORD=true
```

### Component

The sign up form is rendered by `SignUpMethodsContainer`:

```tsx {% title="packages/auth/src/components/sign-up-methods-container.tsx" %}
<SignUpMethodsContainer
  paths={{
    appHome: '/dashboard',
  }}
  providers={{
    password: true,
    magicLink: false,
    passkey: false,
    oAuth: ['google'],
  }}
  displayTermsCheckbox={true}
/>
```

## Email Verification

After registration, users receive a verification email. They must click the link to activate their account.

### Configuration

Email verification is enabled by default in the Better Auth configuration:

```typescript {% title="packages/better-auth/src/auth.ts" %}
emailAndPassword: {
  enabled: true,
  requireEmailVerification: true,  // Require verification
},
emailVerification: {
  sendOnSignUp: true,              // Send email automatically
  autoSignInAfterVerification: true,  // Sign in after verifying
},
```

### Verification Flow

1. User submits registration form
2. User record is created with `emailVerified: false`
3. Verification email is sent with a secure link
4. User clicks link and is redirected to `/auth/verify`
5. Email is marked as verified
6. User is automatically signed in (if `autoSignInAfterVerification` is true)

### Email Template

The verification email is sent using your configured mailer. Customize the template at:

```
packages/better-auth/src/emails/send-verification-email.ts
```

## Account Creation

When a user registers, the kit automatically creates:

1. **User record** - Core identity with email, name, password hash
2. **Personal account** - Default workspace for the user

The personal account allows users to use the app immediately without creating an organization. Users can later create or join organizations.

### Database Records

```sql
-- User table
INSERT INTO users (id, email, name, email_verified, created_at)
VALUES ('user_123', 'user@example.com', 'John Doe', false, NOW());

-- Account table (personal workspace)
INSERT INTO accounts (id, name, is_personal_account, primary_owner_user_id)
VALUES ('account_123', 'Personal', true, 'user_123');
```

## Social Provider Registration

Users can also register via social providers. In the current repo, Google is wired by default. When signing in with a social provider for the first time, an account is automatically created.

Social registration:
- Does not require a password
- Email is automatically verified (trusted from provider)
- Profile data (name, avatar) is imported from the provider

See [Sign In > Social Provider Sign In](./sign-in#social-provider-sign-in) for configuration.

## Magic Link Registration

When magic link is enabled, users can register by simply entering their email. A link is sent that both verifies the email and signs them in.

```bash {% title="apps/web/.env.local" %}
NEXT_PUBLIC_AUTH_MAGIC_LINK=true
```

## Post-Registration

After successful registration and email verification, users are redirected to their dashboard:

```typescript
// Default redirect path
const redirectPath = process.env.NEXT_PUBLIC_APP_HOME_PATH ?? '/dashboard';
```

### Customizing the Redirect

To change where users land after registration, set the environment variable:

```bash {% title="apps/web/.env.local" %}
NEXT_PUBLIC_APP_HOME_PATH=/onboarding
```

## Programmatic Registration

For custom registration flows, use the auth client directly:

```typescript
'use client';

import { authClient } from '@kit/better-auth/client';

async function handleSignUp(name: string, email: string, password: string) {
  const result = await authClient.signUp.email({
    name,
    email,
    password,
  });

  if (result.error) {
    console.error(result.error.message);
    return;
  }

  // Show "check your email" message
  alert('Please check your email to verify your account');
}
```

## Adding Terms Acceptance

To require users to accept terms of service, the sign up form includes an optional checkbox:

```tsx {% title="packages/auth/src/components/terms-and-conditions-form-field.tsx" %}
<TermsAndConditionsFormField
  termsPath="/terms"
  privacyPath="/privacy"
/>
```

Configure the paths to your terms and privacy policy pages.

## Validation Rules

The registration form enforces these validations:

| Field | Rules |
|-------|-------|
| Name | Required, 1-100 characters |
| Email | Required, valid email format |
| Password | Required, minimum 8 characters |

### Custom Validation

To add custom password requirements, modify the Zod schema in the sign up form component.

## Common Issues

### "Email already exists" Error

The email is already registered. Direct users to the sign in page or password reset.

### Verification Email Not Received

1. Check spam/junk folder
2. Verify mailer configuration
3. Check that `sendOnSignUp` is `true` in auth config
4. In development, check the console for logged URLs

### User Created but Can't Sign In

Email verification is likely pending. Check the `emailVerified` field in the database.

---

**Previous:** [Sign In ←](./sign-in) | **Next:** [Password Reset →](./password-reset)
