# Sign Up

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

*Canonical: https://makerkit.dev/docs/tanstack-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.

**Route file:** `apps/web/src/routes/auth/sign-up.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" %}
# Enable email/password registration (default: true)
VITE_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, Better Auth writes two rows:

1. **`user` record** - Core identity: `email`, `name`, `emailVerified`, timestamps.
2. **`account` record** - The credential (or OAuth) link for that user. For email/password sign-up it stores the hashed `password` with `providerId = 'credential'`; for social sign-up it stores the provider's `providerId`, `accountId`, and tokens. The `account` table links a user to an authentication method — it is not a workspace or tenant.

There is no separate personal-account/workspace row created at sign-up. A user can operate without any organization; personal vs. organization context is derived at runtime from `session.activeOrganizationId` (unset means personal). Users can later create or join organizations, which populate the `organization` and `member` tables.

### Database Records

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

-- account table (credential link for email/password sign-up)
INSERT INTO "account" (id, account_id, provider_id, user_id, password, created_at, updated_at)
VALUES ('account_123', 'user_123', 'credential', 'user_123', '<hashed-password>', NOW(), NOW());
```

## 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" %}
VITE_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.VITE_APP_HOME_PATH ?? '/dashboard';
```

### Customizing the Redirect

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

```bash {% title="apps/web/.env" %}
VITE_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)
