> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getsabo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy to Vercel

> Deploy your Sabo application to Vercel with step-by-step instructions for environment configuration, database setup, and production optimization.

<Info>
  Vercel is the recommended hosting platform for Sabo. This guide covers importing your project, configuring environment variables, setting up production webhooks, and verifying your deployment works correctly.
</Info>

## Prerequisites

Before deploying, ensure you have:

<AccordionGroup>
  <Accordion title="Required">
    * **Vercel account** ([Sign up free](https://vercel.com/signup))
    * **Git repository** (GitHub, GitLab, or Bitbucket) with your Sabo project pushed
    * **Supabase project** configured with database migration applied ([Database with Supabase](/core-features/database-supabase))
    * **Local environment working** (`pnpm dev` runs successfully with all features)
  </Accordion>

  <Accordion title="Optional (for full features)">
    * **Stripe account** configured for payments ([Setup guide](/core-features/payments-with-stripe))
    * **PostHog account** for analytics ([Setup guide](/core-features/analytics-posthog))
    * **Custom domain** (can be added after initial deployment)
  </Accordion>
</AccordionGroup>

<Check>
  **Local build test:** Run `pnpm build` locally to catch any build errors before deploying.
</Check>

***

## Step-by-Step Deployment

<Steps>
  <Step title="Import project to Vercel">
    Connect your repository to Vercel:

    1. Go to [Vercel Dashboard](https://vercel.com/dashboard)
    2. Click **Add New\...** → **Project**
    3. Select your Git provider and authorize access
    4. Choose your Sabo repository from the list
    5. Vercel will auto-detect Next.js settings:
       * **Framework Preset:** Next.js
       * **Root Directory:** `./` (or `./sabo` if using a monorepo)
       * **Build Command:** `pnpm run build` (runs the `build` script which calls `next build`)
       * **Output Directory:** `.next` (auto-detected)
       * **Install Command:** `pnpm install` (auto-detected from `pnpm-lock.yaml`)

    <Note>
      Sabo uses Next.js 16 with App Router. Vercel automatically detects the correct build configuration. No manual settings needed.
    </Note>

    <Check>
      Project imported successfully. You should see the "Configure Project" screen.
    </Check>
  </Step>

  <Step title="Configure environment variables">
    Add all required environment variables in the Vercel project configuration screen. Click **Environment Variables** and add each variable below.

    ### Core Variables (Required)

    ```bash theme={null}
    # Site URL
    NEXT_PUBLIC_SITE_URL=https://your-project.vercel.app

    # Supabase
    NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
    NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=eyJhbGciOiJIUzI1N...
    SUPABASE_SECRET_KEY=sbp_1234567890abcdef...
    ```

    <Warning>
      **For production**, set `NEXT_PUBLIC_SITE_URL` to your actual domain, not the `.vercel.app` URL. Update this after adding a custom domain.
    </Warning>

    ### Stripe Variables (Required for payments)

    ```bash theme={null}
    # Stripe API Keys
    STRIPE_SECRET_KEY=sk_live_...
    STRIPE_WEBHOOK_SECRET=whsec_...
    NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...

    # Stripe Product Price IDs (optional, for pricing page)
    NEXT_PUBLIC_STRIPE_PRICE_ID_PRO_MONTHLY=price_...
    NEXT_PUBLIC_STRIPE_PRICE_ID_PRO_YEARLY=price_...

    # Stripe Customer Portal Configuration (optional)
    STRIPE_CUSTOMER_PORTAL_CONFIG_ID=bpc_...
    ```

    <Tip>
      **Test mode vs. Production:**

      * For **Production** environment: Use `sk_live_...` and `pk_live_...`
      * For **Preview** environment: You can use `sk_test_...` and `pk_test_...`

      Set environment variable scopes in Vercel to control which keys are used in which environments.
    </Tip>

    ### PostHog Variables (Optional, for analytics)

    ```bash theme={null}
    NEXT_PUBLIC_POSTHOG_KEY=phc_...
    NEXT_PUBLIC_POSTHOG_HOST=https://app.posthog.com
    ```

    <Note>
      PostHog is optional. Sabo only activates analytics if these variables are set.
    </Note>

    ### Testing Variables (Optional, for E2E tests)

    ```bash theme={null}
    TEST_USER_EMAIL=test@example.com
    TEST_USER_PASSWORD=secure_test_password
    ```

    <Note>
      Only needed if running Playwright tests in CI/CD (e.g., GitHub Actions). Not required for deployment.
    </Note>

    ### Environment Variable Scopes

    For each variable, select the appropriate scope:

    * **Production** - Live site environment
    * **Preview** - Pull request and branch preview deployments
    * **Development** - Local development (usually not needed; use `.env.local`)

    <Tip>
      Use **Production** scope for all variables initially. You can refine scopes later (e.g., test Stripe keys for Preview, live keys for Production).
    </Tip>

    <Check>
      All environment variables added and saved in Vercel.
    </Check>
  </Step>

  <Step title="Update Supabase Auth URLs">
    Configure Supabase to allow authentication from your Vercel domain:

    1. Go to [Supabase Dashboard](https://supabase.com/dashboard) → Your Project

    2. Navigate to **Authentication** → **URL Configuration**

    3. Update **Site URL** to:
       ```
       https://your-project.vercel.app
       ```
       (or your custom domain: `https://yourdomain.com`)

    4. Add to **Redirect URLs** (comma-separated list):
       ```
       https://your-project.vercel.app/auth/callback
       https://yourdomain.com/auth/callback
       ```

    5. For preview deployments, add a wildcard pattern:
       ```
       https://*-your-project.vercel.app/auth/callback
       ```

    <Note>
      The wildcard pattern (`https://*-your-project.vercel.app/auth/callback`) allows all Vercel preview URLs to work with authentication. This is optional but recommended for testing auth in preview deployments.
    </Note>

    <Check>
      Supabase allows authentication callbacks from your Vercel domains.
    </Check>
  </Step>

  <Step title="Configure Stripe webhook (for payments)">
    Set up a production webhook endpoint in Stripe:

    1. Go to [Stripe Dashboard](https://dashboard.stripe.com/webhooks)

    2. **Toggle to Live mode** (top-right corner)

    3. Click **Add endpoint**

    4. Set **Endpoint URL** to:
       ```
       https://yourdomain.com/api/webhooks/stripe
       ```
       (Use your actual domain, not `.vercel.app`)

    5. Select **Events to send**:
       * `customer.subscription.created`
       * `customer.subscription.updated`
       * `customer.subscription.deleted`
       * `invoice.payment_succeeded`
       * `invoice.payment_failed`

    6. Click **Add endpoint**

    7. Copy the **Signing secret** (starts with `whsec_...`)

    8. Go back to Vercel Dashboard → Your Project → **Settings** → **Environment Variables**

    9. Update `STRIPE_WEBHOOK_SECRET` with the new signing secret

    10. **Redeploy** your project for the new secret to take effect

    <Warning>
      **Critical:** Use separate webhook endpoints and secrets for test mode (local development) and live mode (production). Never use the same webhook secret for both.
    </Warning>

    <Tip>
      **Preview deployments:** If you want to test webhooks in preview deployments, create a separate webhook endpoint with test mode keys and a different signing secret.
    </Tip>

    <Check>
      Stripe webhook endpoint created, signing secret added to Vercel, and project redeployed.
    </Check>
  </Step>

  <Step title="Deploy to production">
    Trigger your first deployment:

    **Option A: Deploy from Vercel Dashboard**

    1. In the Vercel project configuration screen, click **Deploy**
    2. Vercel will build your project and deploy it
    3. Monitor the build logs for errors

    **Option B: Deploy via Git push**

    1. Make a commit to your repository:
       ```bash theme={null}
       git add .
       git commit -m "Deploy to production"
       git push origin main
       ```
    2. Vercel automatically deploys on every push to your main branch

    <Check>
      Build succeeds and deployment completes. You'll see "Ready" status with a URL.
    </Check>

    <Note>
      Build time: \~2-4 minutes for a fresh Sabo deployment. Subsequent deploys are faster (\~1-2 minutes) thanks to caching.
    </Note>
  </Step>

  <Step title="Verify deployment">
    Test that your deployed application works correctly:

    <Tabs>
      <Tab title="Marketing Pages">
        Test public pages (no auth required):

        * **Homepage:** `https://yourdomain.com/`
        * **Pricing:** `https://yourdomain.com/pricing`
        * **Contact:** `https://yourdomain.com/contact`
        * **Blog:** `https://yourdomain.com/blog`
        * **Changelog:** `https://yourdomain.com/changelog`
        * **Legal pages:** `/privacy`, `/terms-of-service`, `/cookie-policy`

        <Check>
          All marketing pages load correctly with proper styling and navigation.
        </Check>
      </Tab>

      <Tab title="Authentication">
        Test authentication flows:

        1. **Sign up:** `https://yourdomain.com/sign-up`
           * Enter email and password
           * Check email for verification link
           * Click link to verify account
           * Should redirect to `/dashboard`

        2. **Sign in:** `https://yourdomain.com/sign-in`
           * Enter credentials
           * Should redirect to `/dashboard`

        3. **OAuth (if configured):**
           * Click Google/GitHub/Apple sign-in
           * Authorize in provider popup
           * Should redirect to `/dashboard`

        4. **Password reset:**
           * Go to `/forgot-password`
           * Enter email
           * Check email for reset link
           * Set new password
           * Should redirect to `/sign-in`

        <Check>
          All authentication flows work without errors. Users can sign up, verify email, and access dashboard.
        </Check>
      </Tab>

      <Tab title="Dashboard">
        Test protected routes (requires sign-in):

        * **Dashboard:** `https://yourdomain.com/dashboard`
        * **Settings pages:**
          * `/dashboard/settings/general`
          * `/dashboard/settings/account`
          * `/dashboard/settings/billing`
          * `/dashboard/settings/notifications`

        <Check>
          Dashboard loads with sidebar, navigation works, and settings pages display correctly.
        </Check>
      </Tab>

      <Tab title="Payments (Stripe)">
        Test subscription flow:

        1. **Not signed in:**
           * Go to `/pricing`
           * Click "Upgrade to Pro" or "Start Free"
           * Should redirect to `/sign-in`

        2. **Signed in:**
           * Go to `/pricing`
           * Click "Upgrade to Pro"
           * Complete checkout with Stripe test card: `4242 4242 4242 4242`
           * Should redirect to `/success`
           * Check `/dashboard/settings/billing` to see subscription status

        3. **Customer Portal:**
           * Go to `/dashboard/settings/billing`
           * Click "Manage Subscription"
           * Should open Stripe Customer Portal
           * Test canceling/updating subscription

        4. **Webhook verification:**
           * Go to Stripe Dashboard → Webhooks → Your endpoint
           * Click **Send test webhook**
           * Select `invoice.payment_succeeded`
           * Check Vercel logs for successful processing

        <Check>
          Payments complete successfully, subscriptions sync to database, and webhooks process correctly.
        </Check>

        <Warning>
          Use **test mode** Stripe keys for initial testing. Switch to **live mode** only when ready for real payments.
        </Warning>
      </Tab>
    </Tabs>

    <Check>
      All core features verified and working in production.
    </Check>
  </Step>

  <Step title="Add custom domain (optional)">
    Connect a custom domain to your Vercel project:

    1. Go to Vercel Dashboard → Your Project → **Settings** → **Domains**
    2. Click **Add** and enter your domain (e.g., `yourdomain.com`)
    3. Follow DNS configuration instructions:
       * **For root domain (`yourdomain.com`)**: Add A record pointing to Vercel's IP
       * **For subdomain (`www.yourdomain.com`)**: Add CNAME record pointing to `cname.vercel-dns.com`
    4. Wait for DNS propagation (usually 5-60 minutes)
    5. Vercel automatically issues SSL certificate via Let's Encrypt

    **After domain is active:**

    1. Update environment variable in Vercel:
       ```bash theme={null}
       NEXT_PUBLIC_SITE_URL=https://yourdomain.com
       ```

    2. Update Supabase Auth URLs:
       * Site URL: `https://yourdomain.com`
       * Add redirect URL: `https://yourdomain.com/auth/callback`

    3. Update Stripe webhook endpoint URL:
       * Change endpoint URL to: `https://yourdomain.com/api/webhooks/stripe`
       * Copy new signing secret to Vercel env vars

    4. **Redeploy** your project for all changes to take effect

    <Check>
      Custom domain is active with SSL, all URLs updated, and deployment successful.
    </Check>
  </Step>

  <Step title="Set up preview deployments">
    Vercel automatically creates preview deployments for every branch and pull request:

    * **Preview URLs:** `https://your-project-git-branchname-yourteam.vercel.app`
    * **Pull request previews:** Each PR gets a unique preview URL
    * **Automatic deployment:** Push to any branch triggers a preview build

    **Preview-specific environment variables:**

    You can set different environment variables for Preview deployments (e.g., test Stripe keys, staging Supabase project):

    1. Go to Vercel Dashboard → Your Project → **Settings** → **Environment Variables**
    2. Add variables with **Preview** scope
    3. Previews will use these instead of Production values

    **Useful for:**

    * Testing with Stripe test mode
    * Using a staging Supabase database
    * Sharing work-in-progress with your team

    <Tip>
      Add comments in pull requests to share preview URLs with team members for review.
    </Tip>

    <Check>
      Preview deployments working. Each branch push creates a new preview URL.
    </Check>
  </Step>
</Steps>

***

## Production Optimization

### Performance

Sabo is optimized for Vercel out of the box:

* **Automatic CDN caching** for static assets
* **Edge runtime** for fast middleware execution
* **Image optimization** via Next.js Image component
* **Static generation for blog and changelog** (built from MDX at deploy time—redeploy when content changes)
* **Server-side rendering (SSR)** for dynamic pages

<Check>
  No additional configuration needed. Vercel handles all optimizations automatically.
</Check>

### Build Settings

Default build settings work for most cases:

```bash theme={null}
Build Command: next build
Install Command: pnpm install
Output Directory: .next
Node Version: 20.x (auto-detected)
```

<Tip>
  If deploying from a monorepo, set **Root Directory** to `sabo` (or your Sabo package path).
</Tip>

### Environment Management

Organize environment variables by environment:

| Environment     | Use Case                  | Example Keys                       |
| --------------- | ------------------------- | ---------------------------------- |
| **Production**  | Live site with real users | `sk_live_...`, production Supabase |
| **Preview**     | PR/branch testing         | `sk_test_...`, staging Supabase    |
| **Development** | Local dev (`.env.local`)  | `sk_test_...`, local Supabase      |

<Note>
  Development environment variables are **not** synced to Vercel. Use `.env.local` for local development.
</Note>

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Build fails with 'Module not found' or TypeScript errors">
    **Symptoms:**

    * Build logs show module import errors
    * TypeScript compilation fails

    **Solutions:**

    1. **Verify all dependencies are in `package.json`:**
       ```bash theme={null}
       pnpm install
       git add package.json pnpm-lock.yaml
       git commit -m "Update dependencies"
       git push
       ```

    2. **Check for missing environment variables:**
       * Build-time code referencing env vars will fail if vars are missing
       * Add missing vars in Vercel Dashboard

    3. **Clear build cache:**
       * Vercel Dashboard → Deployments → Latest build → **...** menu → **Redeploy**
       * Check "Clear build cache and redeploy"

    4. **Local build test:**
       ```bash theme={null}
       pnpm build
       ```
       If it fails locally, fix errors before deploying.
  </Accordion>

  <Accordion title="Environment variables not working">
    **Symptoms:**

    * `process.env.VARIABLE_NAME` is `undefined`
    * Features work locally but not in production

    **Solutions:**

    1. **Check variable naming:**
       * Client-side variables **must** start with `NEXT_PUBLIC_`
       * Server-only variables should **not** have `NEXT_PUBLIC_` prefix

    2. **Verify variable scope:**
       * Go to Vercel Dashboard → Settings → Environment Variables
       * Ensure variables have correct scope (Production/Preview/Development)

    3. **Redeploy after adding variables:**
       * Environment variables are only loaded at build time
       * After adding/changing vars, trigger a new deployment

    4. **Check for typos:**
       * Variable names are case-sensitive
       * `SUPABASE_URL` ≠ `SUPABASE_url`
  </Accordion>

  <Accordion title="Authentication callback fails (Supabase)">
    **Symptoms:**

    * After signing in with OAuth, user sees error page
    * Email verification links redirect to error page
    * Console shows CORS or redirect errors

    **Solutions:**

    1. **Check Supabase Redirect URLs:**
       * Go to Supabase Dashboard → Authentication → URL Configuration
       * Ensure your Vercel domain is in **Redirect URLs** list
       * Format: `https://yourdomain.com/auth/callback`

    2. **Verify Site URL matches:**
       * `NEXT_PUBLIC_SITE_URL` in Vercel **must match** Supabase Site URL
       * Include protocol (`https://`), no trailing slash

    3. **Check for browser redirects:**
       * Open browser DevTools → Network tab
       * Look for redirect chain
       * Verify final redirect goes to `/auth/callback`

    4. **Test with different browsers/incognito:**
       * Clear browser cache and cookies
       * Try in incognito/private window
       * Some browsers block third-party cookies
  </Accordion>

  <Accordion title="Stripe webhook not receiving events">
    **Symptoms:**

    * Subscriptions don't update in database
    * Payments succeed but user subscription status unchanged
    * Stripe Dashboard shows "Endpoint not responding"

    **Solutions:**

    1. **Verify endpoint URL is correct:**
       * Stripe Dashboard → Webhooks → Your endpoint
       * URL should be: `https://yourdomain.com/api/webhooks/stripe`
       * Must use **custom domain**, not `.vercel.app` (for live mode)

    2. **Check webhook signing secret:**
       * Ensure `STRIPE_WEBHOOK_SECRET` in Vercel matches endpoint secret
       * Use **live mode** secret (`whsec_...`) for production

    3. **Test webhook delivery:**
       * Stripe Dashboard → Webhooks → Your endpoint
       * Click **Send test webhook**
       * Select event type (e.g., `invoice.payment_succeeded`)
       * Check Vercel logs for processing

    4. **Review Vercel Function Logs:**
       * Vercel Dashboard → Your Project → **Logs**
       * Filter by `/api/webhooks/stripe`
       * Look for errors or webhook signature verification failures

    5. **Ensure events are selected:**
       * Webhook endpoint must listen for:
         * `customer.subscription.created`
         * `customer.subscription.updated`
         * `customer.subscription.deleted`
         * `invoice.payment_succeeded`
         * `invoice.payment_failed`
  </Accordion>

  <Accordion title="PostHog analytics not tracking events">
    **Symptoms:**

    * No events appear in PostHog dashboard
    * Console shows "PostHog is not initialized"

    **Solutions:**

    1. **Verify environment variables are set:**
       ```bash theme={null}
       NEXT_PUBLIC_POSTHOG_KEY=phc_...
       NEXT_PUBLIC_POSTHOG_HOST=https://app.posthog.com
       ```

    2. **Redeploy after adding PostHog vars:**
       * PostHog only initializes if env vars are present at build time

    3. **Check browser console:**
       * Open DevTools → Console
       * Look for PostHog initialization messages
       * Check Network tab for requests to `app.posthog.com`

    4. **Verify PostHog project is active:**
       * PostHog Dashboard → Project Settings
       * Ensure project is not paused or archived
  </Accordion>

  <Accordion title="Production build is slow or times out">
    **Symptoms:**

    * Vercel build exceeds time limit (10 minutes on free plan)
    * Build gets stuck on specific step

    **Solutions:**

    1. **Optimize dependencies:**
       ```bash theme={null}
       # Remove unused dependencies
       pnpm prune

       # Update outdated packages
       pnpm update
       ```

    2. **Check for large files in repo:**
       * Avoid committing `node_modules/`, `.next/`, or large assets
       * Use `.gitignore` to exclude build artifacts

    3. **Upgrade Vercel plan:**
       * Free tier: 10-minute build limit
       * Pro tier: 45-minute build limit

    4. **Split large pages:**
       * Use dynamic imports for heavy components
       * Implement code splitting for route segments
  </Accordion>

  <Accordion title="404 errors on page refresh">
    **Symptoms:**

    * Direct URL navigation works
    * Refreshing page shows 404

    **Solutions:**

    1. **This should not happen with Vercel + Next.js App Router.**
       * Vercel automatically handles Next.js routing

    2. **Check Vercel routing configuration:**
       * Vercel Dashboard → Project Settings → General
       * Ensure "Framework Preset" is set to **Next.js**

    3. **Verify build output:**
       * Check Vercel build logs
       * Ensure `.next` directory contains expected routes

    4. **Test with `vercel dev`:**
       ```bash theme={null}
       npm i -g vercel
       vercel dev
       ```
       Run locally with Vercel's dev server to debug routing
  </Accordion>
</AccordionGroup>

***

## Continuous Deployment

Vercel automatically deploys on every push to your Git repository:

### Deployment Triggers

| Action                   | Result                                |
| ------------------------ | ------------------------------------- |
| Push to `main` branch    | Deploys to **Production**             |
| Push to any other branch | Creates **Preview** deployment        |
| Open pull request        | Creates **Preview** with comment link |
| Merge PR                 | Deploys to **Production**             |

### Deployment Protection

Enable deployment protection for production:

1. Vercel Dashboard → Project Settings → **Git**
2. Enable **Production Deployment Protection**
3. Only designated team members can approve production deploys

<Tip>
  Set up Vercel GitHub integration to automatically comment on PRs with preview URLs.
</Tip>
