Skip to main content

Overview

Ticket Hub uses @t3-oss/env-nextjs for type-safe environment variable validation. This ensures that all required variables are set before the app starts, preventing runtime errors.

Environment Schema

The environment configuration is defined in src/env.ts:
src/env.ts
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

const env = createEnv({
  server: {
    NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
    PORT: z.coerce.number().default(3000).optional(),
    CLERK_SECRET_KEY: z.string().min(1),
    CONVEX_DEPLOYMENT: z.string().min(1),
    CLERK_WEBHOOK_SECRET: z.string().min(1),
    STRIPE_SECRET_KEY: z.string().min(1),
    VERCEL_PROJECT_PRODUCTION_URL: z.string().min(1),
    STRIPE_WEBHOOK_SECRET: z.string().min(1),
    CONVEX_DEPLOY_KEY: z.string().min(1),
  },
  client: {
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
    NEXT_PUBLIC_APP_URL: z.string(),
    NEXT_PUBLIC_CLERK_SIGN_IN_URL: z.string().min(1),
    NEXT_PUBLIC_CLERK_SIGN_UP_URL: z.string().min(1),
    NEXT_PUBLIC_CONVEX_URL: z.string().min(1),
  },
  runtimeEnv: {
    NODE_ENV: process.env.NODE_ENV,
    PORT: process.env.PORT,
    CLERK_SECRET_KEY: process.env.CLERK_SECRET_KEY,
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
    NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
    NEXT_PUBLIC_CLERK_SIGN_IN_URL: process.env.NEXT_PUBLIC_CLERK_SIGN_IN_URL,
    NEXT_PUBLIC_CLERK_SIGN_UP_URL: process.env.NEXT_PUBLIC_CLERK_SIGN_UP_URL,
    NEXT_PUBLIC_CONVEX_URL: process.env.NEXT_PUBLIC_CONVEX_URL,
    CONVEX_DEPLOYMENT: process.env.CONVEX_DEPLOYMENT,
    CLERK_WEBHOOK_SECRET: process.env.CLERK_WEBHOOK_SECRET,
    STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
    VERCEL_PROJECT_PRODUCTION_URL: process.env.VERCEL_PROJECT_PRODUCTION_URL,
    STRIPE_WEBHOOK_SECRET: process.env.STRIPE_WEBHOOK_SECRET,
    CONVEX_DEPLOY_KEY: process.env.CONVEX_DEPLOY_KEY,
  },
  skipValidation: !!process.env.SKIP_ENV_VALIDATION,
  emptyStringAsUndefined: true,
});

export default env;
The schema automatically validates all environment variables at build time. Missing or invalid variables will cause the build to fail with clear error messages.

Required Environment Variables

Clerk Authentication

1

Get Clerk API Keys

  1. Go to clerk.com and sign in
  2. Select your application
  3. Navigate to API Keys
  4. Copy the keys
2

Add to .env.local

# Clerk Authentication
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
CLERK_WEBHOOK_SECRET=whsec_...

# Clerk URLs
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
string
required
Client-side publishable key from Clerk dashboard.
  • Prefix: pk_test_ (test) or pk_live_ (production)
  • Safe to expose in client-side code
  • Used to initialize Clerk in the browser
CLERK_SECRET_KEY
string
required
Server-side secret key from Clerk dashboard.
  • Prefix: sk_test_ (test) or sk_live_ (production)
  • Keep this secure - never expose in client code
  • Used for server-side API calls
CLERK_WEBHOOK_SECRET
string
required
Signing secret for verifying Clerk webhook requests.
  • Prefix: whsec_
  • Found in Clerk dashboard → Webhooks → Your endpoint
  • Ensures webhooks are authentic
NEXT_PUBLIC_CLERK_SIGN_IN_URL
string
default:"/sign-in"
Path to your sign-in page. Must match Clerk dashboard configuration.
NEXT_PUBLIC_CLERK_SIGN_UP_URL
string
default:"/sign-up"
Path to your sign-up page. Must match Clerk dashboard configuration.

Convex Backend

1

Initialize Convex

Run Convex development mode:
npx convex dev
This will:
  • Create a Convex project (first time)
  • Deploy your schema and functions
  • Output your deployment URL
2

Copy Convex URL

After running npx convex dev, copy the URL displayed:
NEXT_PUBLIC_CONVEX_URL=https://your-deployment.convex.cloud
3

Get deployment credentials

For production deployments:
  1. Go to convex.dev
  2. Select your project
  3. Go to SettingsDeploy Keys
  4. Create a new deploy key
CONVEX_DEPLOYMENT=your-deployment-name
CONVEX_DEPLOY_KEY=...
NEXT_PUBLIC_CONVEX_URL
string
required
Your Convex deployment URL.
  • Format: https://[deployment-name].convex.cloud
  • Automatically generated when you run npx convex dev
  • Different for each environment (dev, staging, prod)
CONVEX_DEPLOYMENT
string
required
Your Convex deployment identifier.
  • Found in Convex dashboard → Settings
  • Used for production deployments
  • Format: prod:your-deployment-name
CONVEX_DEPLOY_KEY
string
required
Deploy key for automated deployments.
  • Created in Convex dashboard → SettingsDeploy Keys
  • Required for CI/CD pipelines
  • Keep this secret

Stripe Payments

1

Get Stripe API Keys

  1. Go to stripe.com and sign in
  2. Navigate to DevelopersAPI Keys
  3. Copy your Secret Key
2

Set up Stripe webhooks

  1. Go to DevelopersWebhooks
  2. Click Add endpoint
  3. Enter URL: https://your-app.vercel.app/api/webhooks/stripe
  4. Select events:
    • payment_intent.succeeded
    • payment_intent.payment_failed
    • charge.refunded
  5. Copy the Signing Secret
3

Add to .env.local

# Stripe
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_SECRET_KEY
string
required
Your Stripe secret API key.
  • Prefix: sk_test_ (test mode) or sk_live_ (live mode)
  • Found in Stripe dashboard → API Keys
  • Used for creating payment intents and processing charges
  • Never expose this in client-side code
STRIPE_WEBHOOK_SECRET
string
required
Signing secret for Stripe webhook verification.
  • Prefix: whsec_
  • Found in Stripe dashboard → Webhooks → Your endpoint
  • Ensures webhook events are genuine

Application Configuration

NEXT_PUBLIC_APP_URL
string
required
The public URL of your application.
  • Development: http://localhost:3000
  • Production: https://your-app.vercel.app
  • Used for redirects and callback URLs
VERCEL_PROJECT_PRODUCTION_URL
string
required
Your Vercel production URL.
  • Format: your-project.vercel.app (without https://)
  • Automatically set by Vercel in production
  • For local development, use your expected production URL
NODE_ENV
string
default:"development"
Application environment.
  • Values: development, test, production
  • Automatically set by Next.js
  • Optional to set manually
PORT
number
default:"3000"
Port for local development server.
  • Default: 3000
  • Optional - only needed if you want a different port

Complete .env.local Example

.env.local
# Application
NODE_ENV=development
NEXT_PUBLIC_APP_URL=http://localhost:3000
VERCEL_PROJECT_PRODUCTION_URL=ticket-hub.vercel.app

# Clerk Authentication
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_ZXhhbXBsZS1jbGVyay0xMjM0NTY3OA==
CLERK_SECRET_KEY=sk_test_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890
CLERK_WEBHOOK_SECRET=whsec_abcdefghijklmnopqrstuvwxyz123456
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up

# Convex
NEXT_PUBLIC_CONVEX_URL=https://happy-elephant-123.convex.cloud
CONVEX_DEPLOYMENT=prod:happy-elephant-123
CONVEX_DEPLOY_KEY=prod:happy-elephant-123|1234567890abcdef

# Stripe
STRIPE_SECRET_KEY=sk_test_51AbCdEf123456789GhIjKlMnOpQrStUvWxYz
STRIPE_WEBHOOK_SECRET=whsec_1234567890abcdefghijklmnopqrstuvwxyz
Never commit your .env.local file to version control. Add it to .gitignore.

Environment-Specific Configuration

Development

.env.local
NODE_ENV=development
NEXT_PUBLIC_APP_URL=http://localhost:3000

# Use Clerk/Stripe test keys
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...

# Use Convex dev deployment
NEXT_PUBLIC_CONVEX_URL=https://dev-deployment.convex.cloud

Production

.env.production
NODE_ENV=production
NEXT_PUBLIC_APP_URL=https://ticket-hub.vercel.app
VERCEL_PROJECT_PRODUCTION_URL=ticket-hub.vercel.app

# Use Clerk/Stripe live keys
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_...
STRIPE_SECRET_KEY=sk_live_...

# Use Convex production deployment
NEXT_PUBLIC_CONVEX_URL=https://prod-deployment.convex.cloud
CONVEX_DEPLOYMENT=prod:your-deployment

Validation and Type Safety

Accessing Environment Variables

Import from src/env.ts for type-safe access:
import env from "@/env";

// ✅ Type-safe and validated
const clerkKey = env.CLERK_SECRET_KEY;
const convexUrl = env.NEXT_PUBLIC_CONVEX_URL;

// ❌ Avoid accessing process.env directly
// const key = process.env.CLERK_SECRET_KEY; // Not type-safe

Skipping Validation

For Docker builds or specific CI scenarios:
SKIP_ENV_VALIDATION=true
Only skip validation when absolutely necessary. Missing variables will cause runtime errors.

Troubleshooting

Check that all required variables are set in your .env.local file. The error message will tell you exactly which variables are missing or invalid.
Make sure:
  • Variables start with NEXT_PUBLIC_ prefix
  • You’ve restarted the dev server after adding them
  • They’re in .env.local, not just exported in your shell
Verify:
  • The webhook URL is correct and publicly accessible
  • The signing secret matches exactly (no extra spaces)
  • You’re using the correct environment (test vs. live)
Run npx convex dev to:
  • Generate the Convex deployment
  • Get the correct NEXT_PUBLIC_CONVEX_URL
  • Ensure Convex is properly initialized

Next Steps

Quickstart

Get the app running with these environment variables

Authentication

Deep dive into Clerk authentication setup

Stripe Integration

Set up payment processing with Stripe

API Reference

Explore the Convex API functions

Build docs developers (and LLMs) love