# Environment Variables Reference for the Tanstack Start Supabase SaaS Kit

> Complete reference for all environment variables in the Tanstack Start Supabase SaaS Kit, including Supabase, Stripe, email, and feature flag configuration.

*Canonical: https://makerkit.dev/docs/tanstack-supabase/configuration/environment-variables*

---

This page documents all environment variables used by the Tanstack Start Supabase SaaS Kit. Variables are organized by category and include their purpose, required status, and default values.

## Environment File Structure

| File | Purpose | Git Status |
|------|---------|------------|
| `.env` | Shared settings across all environments | Committed |
| `.env.development` | Development-specific overrides | Committed |
| `.env.production` | Production-specific settings | Committed |
| `.env.local` | Local secrets and overrides | Git-ignored |

**Priority order**: `.env.local` > `.env.development`/`.env.production` > `.env`

## Required Variables

These variables must be set for the application to start:

```bash
# Supabase (required)
VITE_SUPABASE_URL=https://yourproject.supabase.co
VITE_SUPABASE_PUBLIC_KEY=your-public-key
SUPABASE_SECRET_KEY=your-service-role-key

# App identity (required)
VITE_SITE_URL=https://yourapp.com
VITE_PRODUCT_NAME=Your Product
VITE_SITE_TITLE="Your Product - Tagline"
VITE_SITE_DESCRIPTION="Your product description"
```

## Core Configuration

### Site Identity

```bash
VITE_SITE_URL=https://example.com
VITE_PRODUCT_NAME=Makerkit
VITE_SITE_TITLE="Makerkit - Build SaaS Faster"
VITE_SITE_DESCRIPTION="Production-ready SaaS starter kit"
VITE_DEFAULT_LOCALE=en
```

| Variable | Required | Description |
|----------|----------|-------------|
| `VITE_SITE_URL` | Yes | Full URL with protocol |
| `VITE_PRODUCT_NAME` | Yes | Product name shown in UI |
| `VITE_SITE_TITLE` | Yes | Browser title and SEO |
| `VITE_SITE_DESCRIPTION` | Yes | Meta description |
| `VITE_DEFAULT_LOCALE` | No | Default language (default: `en`) |

### Theme

```bash
VITE_DEFAULT_THEME_MODE=light
VITE_THEME_COLOR="#ffffff"
VITE_THEME_COLOR_DARK="#0a0a0a"
VITE_ENABLE_THEME_TOGGLE=true
```

| Variable | Options | Default | Description |
|----------|---------|---------|-------------|
| `VITE_DEFAULT_THEME_MODE` | `light`, `dark`, `system` | `light` | Initial theme |
| `VITE_THEME_COLOR` | Hex color | Required | Light theme color |
| `VITE_THEME_COLOR_DARK` | Hex color | Required | Dark theme color |
| `VITE_ENABLE_THEME_TOGGLE` | `true`, `false` | `true` | Allow theme switching |

## Supabase Configuration

```bash
VITE_SUPABASE_URL=https://yourproject.supabase.co
VITE_SUPABASE_PUBLIC_KEY=your-public-key
SUPABASE_SECRET_KEY=your-service-role-key
SUPABASE_DB_WEBHOOK_SECRET=your-webhook-secret
```

| Variable | Required | Description |
|----------|----------|-------------|
| `VITE_SUPABASE_URL` | Yes | Supabase project URL |
| `VITE_SUPABASE_PUBLIC_KEY` | Yes | Public anon key |
| `SUPABASE_SECRET_KEY` | Yes | Service role key (keep secret) |
| `SUPABASE_DB_WEBHOOK_SECRET` | No | Webhook verification secret |

{% alert type="warning" title="Legacy Key Names" %}
If you're using a version prior to 2.12.0, use `VITE_SUPABASE_ANON_KEY` and `SUPABASE_SERVICE_ROLE_KEY` instead.
{% /alert %}

## Authentication

```bash
VITE_AUTH_PASSWORD=true
VITE_AUTH_MAGIC_LINK=false
VITE_AUTH_OTP=false
VITE_AUTH_PASSKEY=false
VITE_AUTH_IDENTITY_LINKING=false
VITE_CAPTCHA_SITE_KEY=
CAPTCHA_SECRET_TOKEN=
VITE_CAPTCHA_WIDGET_SIZE=invisible
VITE_DISPLAY_TERMS_AND_CONDITIONS_CHECKBOX=false
```

| Variable | Default | Description |
|----------|---------|-------------|
| `VITE_AUTH_PASSWORD` | `true` | Enable password auth |
| `VITE_AUTH_MAGIC_LINK` | `false` | Enable magic link auth |
| `VITE_AUTH_OTP` | `false` | Enable OTP auth |
| `VITE_AUTH_PASSKEY` | `false` | Enable passkey (WebAuthn) auth |
| `VITE_AUTH_IDENTITY_LINKING` | `false` | Allow identity linking |
| `VITE_CAPTCHA_SITE_KEY` | - | Cloudflare Turnstile site key |
| `CAPTCHA_SECRET_TOKEN` | - | Cloudflare Turnstile secret |
| `VITE_CAPTCHA_WIDGET_SIZE` | `invisible` | Turnstile widget size. Set to `normal` or `compact` with a Managed site key |
| `VITE_DISPLAY_TERMS_AND_CONDITIONS_CHECKBOX` | `false` | Show terms checkbox |

### Password Requirements

```bash
VITE_PASSWORD_REQUIRE_UPPERCASE=false
VITE_PASSWORD_REQUIRE_NUMBERS=false
VITE_PASSWORD_REQUIRE_SPECIAL_CHARS=false
```

## Navigation and Layout

```bash
VITE_USER_NAVIGATION_STYLE=sidebar
VITE_HOME_SIDEBAR_COLLAPSED=false
VITE_SIDEBAR_COLLAPSIBLE_STYLE=icon
VITE_ENABLE_SIDEBAR_TRIGGER=true
```

| Variable | Options | Default | Description |
|----------|---------|---------|-------------|
| `VITE_USER_NAVIGATION_STYLE` | `sidebar`, `header` | `sidebar` | App navigation layout (personal + team) |
| `VITE_HOME_SIDEBAR_COLLAPSED` | `true`, `false` | `false` | Start collapsed |
| `VITE_SIDEBAR_COLLAPSIBLE_STYLE` | `offcanvas`, `icon`, `none` | `icon` | Collapse behavior |
| `VITE_ENABLE_SIDEBAR_TRIGGER` | `true`, `false` | `true` | Show collapse button |

## Feature Flags

```bash
VITE_ACCOUNT_MODE=hybrid
VITE_ENABLE_THEME_TOGGLE=true
VITE_ENABLE_PERSONAL_ACCOUNT_DELETION=false
VITE_ENABLE_PERSONAL_ACCOUNT_BILLING=false
VITE_ENABLE_TEAM_ACCOUNTS_CREATION=true
VITE_ENABLE_TEAM_ACCOUNTS_DELETION=false
VITE_ENABLE_TEAM_ACCOUNTS_BILLING=false
VITE_ENABLE_NOTIFICATIONS=true
VITE_REALTIME_NOTIFICATIONS=false
VITE_ENABLE_VERSION_UPDATER=false
VITE_LANGUAGE_PRIORITY=application
```

| Variable | Default | Description |
|----------|---------|-------------|
| `VITE_ACCOUNT_MODE` | `hybrid` | `personal-only` \| `organizations-only` \| `hybrid`. Single control for which account surfaces exist; the team-account flags below are derived from and gated by it. |
| `VITE_ENABLE_PERSONAL_ACCOUNT_DELETION` | `false` | Users can delete accounts |
| `VITE_ENABLE_PERSONAL_ACCOUNT_BILLING` | `false` | Personal subscription billing |
| `VITE_ENABLE_TEAM_ACCOUNTS_CREATION` | `true` | Users can create teams |
| `VITE_ENABLE_TEAM_ACCOUNTS_DELETION` | `false` | Users can delete teams |
| `VITE_ENABLE_TEAM_ACCOUNTS_BILLING` | `false` | Team subscription billing |
| `VITE_ENABLE_NOTIFICATIONS` | `true` | In-app notifications |
| `VITE_REALTIME_NOTIFICATIONS` | `false` | Live notification updates |
| `VITE_ENABLE_VERSION_UPDATER` | `false` | Check for updates |
| `VITE_LANGUAGE_PRIORITY` | `application` | `user` or `application` |

## Billing Configuration

### Provider Selection

```bash
VITE_BILLING_PROVIDER=stripe
```

Options: `stripe` or `lemon-squeezy`

### Stripe

```bash
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
```

| Variable | Required | Description |
|----------|----------|-------------|
| `VITE_STRIPE_PUBLISHABLE_KEY` | Yes (Stripe) | Publishable key |
| `STRIPE_SECRET_KEY` | Yes (Stripe) | Secret key |
| `STRIPE_WEBHOOK_SECRET` | Yes (Stripe) | Webhook signing secret |

### Lemon Squeezy

```bash
LEMON_SQUEEZY_SECRET_KEY=your-secret-key
LEMON_SQUEEZY_STORE_ID=your-store-id
LEMON_SQUEEZY_SIGNING_SECRET=your-signing-secret
```

| Variable | Required | Description |
|----------|----------|-------------|
| `LEMON_SQUEEZY_SECRET_KEY` | Yes (LS) | API secret key |
| `LEMON_SQUEEZY_STORE_ID` | Yes (LS) | Store identifier |
| `LEMON_SQUEEZY_SIGNING_SECRET` | Yes (LS) | Webhook signing secret |

## Email Configuration

### Provider Selection

```bash
MAILER_PROVIDER=nodemailer
```

Options: `nodemailer` or `resend`

### Common Settings

```bash
EMAIL_SENDER="Your App <noreply@yourapp.com>"
CONTACT_EMAIL=contact@yourapp.com
```

### Resend

```bash
RESEND_API_KEY=re_...
```

### Nodemailer (SMTP)

```bash
EMAIL_HOST=smtp.provider.com
EMAIL_PORT=587
EMAIL_USER=your-username
EMAIL_PASSWORD=your-password
EMAIL_TLS=true
```

## CMS Configuration

### Provider Selection

```bash
CMS_CLIENT=keystatic
```

Options: `keystatic` or `wordpress`

### Keystatic

```bash
VITE_KEYSTATIC_STORAGE_KIND=local
VITE_KEYSTATIC_CONTENT_PATH=./content
KEYSTATIC_PATH_PREFIX=apps/web
```

For GitHub storage:

```bash
VITE_KEYSTATIC_STORAGE_KIND=github
VITE_KEYSTATIC_STORAGE_REPO=owner/repo
KEYSTATIC_GITHUB_TOKEN=github_pat_...
```

| Variable | Options | Description |
|----------|---------|-------------|
| `VITE_KEYSTATIC_STORAGE_KIND` | `local`, `cloud`, `github` | Storage backend |
| `VITE_KEYSTATIC_CONTENT_PATH` | Path | Content directory |
| `KEYSTATIC_PATH_PREFIX` | Path | Monorepo prefix |
| `VITE_KEYSTATIC_STORAGE_REPO` | `owner/repo` | GitHub repository |
| `KEYSTATIC_GITHUB_TOKEN` | Token | GitHub access token |

### WordPress

```bash
WORDPRESS_API_URL=https://your-site.com/wp-json
```

## Security Best Practices

1. **Never commit secrets**: Use `.env.local` for sensitive values
2. **Use CI/CD variables**: Store production secrets in your deployment platform
3. **Rotate keys regularly**: Especially after team member changes
4. **Validate in production**: The kit validates configuration at build time

## Common Pitfalls

1. **HTTP in production**: `VITE_SITE_URL` must use `https://` in production builds.
2. **Same theme colors**: `VITE_THEME_COLOR` and `VITE_THEME_COLOR_DARK` must be different.
3. **Missing Supabase keys**: The app won't start without valid Supabase credentials.
4. **Forgetting to restart**: After changing environment variables, you may need to restart the development server.
5. **Wrong file for secrets**: Put secrets in `.env.local` (git-ignored), not `.env` (committed).

## Related Topics

- [Application Configuration](/docs/tanstack-supabase/configuration/application-configuration) - Core app settings
- [Authentication Configuration](/docs/tanstack-supabase/configuration/authentication-configuration) - Auth setup
- [Feature Flags](/docs/tanstack-supabase/configuration/feature-flags-configuration) - Toggle features
- [Going to Production](/docs/tanstack-supabase/going-to-production/checklist) - Deployment checklist
