KitRocket

Deployment Issues

Troubleshoot Vercel deployments, production database connections, domains, and webhooks.

Build fails on Vercel

Symptom: Vercel deployment fails during the build step.

Cause: TypeScript errors, missing environment variables, or dependency issues.

Fix:

  1. Build locally first to catch errors before deploying:
pnpm build
  1. Check Vercel build logs: Go to your project > Deployments > click the failed deployment > view build logs. The error is usually near the bottom.

  2. Common build errors:

ErrorFix
Type error: ...Fix the TypeScript error. pnpm build locally shows the same error.
Module not foundCheck import paths. The @/ alias must be configured in tsconfig.json.
env var not foundAdd the variable in Vercel > Settings > Environment Variables.
ENOMEM (out of memory)Add NODE_OPTIONS=--max-old-space-size=4096 as an env var in Vercel.
  1. Check Node.js version: KitRocket requires Node 20+. In Vercel, go to Settings > General > Node.js Version and select 20.x.

Environment variables not available

Symptom: App deploys but crashes with "Missing environment variable" errors.

Cause: Variables not set in Vercel, or set for the wrong environment scope.

Fix:

  1. Go to your Vercel project > Settings > Environment Variables
  2. Add every variable from .env.example
  3. Check the environment scope — each variable can be scoped to Production, Preview, or Development
DATABASE_URL      → Production, Preview (different values if separate databases)
AUTH_SECRET       → Production, Preview
BETTER_AUTH_URL   → Production only (set to your production domain)
  1. Redeploy after adding or changing variables. Variables are injected at build time, not runtime. Click Deployments > three dots on latest > Redeploy.

  2. Client-side variables must start with NEXT_PUBLIC_:

# Available on the client (browser)
NEXT_PUBLIC_POSTHOG_KEY=phc_xxx

# Server-only (API routes, server components)
AUTH_SECRET=xxx

Database connection fails in production

Symptom: App deploys but shows "Database connection failed" or times out on page load.

Cause: Wrong connection string, IP restrictions, or connection pooling issues.

Fix:

  1. Use the connection pooler URL from Supabase (port 6543):
# Correct — pooler on port 6543
DATABASE_URL="postgresql://postgres.[ref]:[pass]@aws-0-[region].pooler.supabase.com:6543/postgres"

# Wrong — direct connection on port 5432 (doesn't work well with serverless)
DATABASE_URL="postgresql://postgres.[ref]:[pass]@aws-0-[region].supabase.com:5432/postgres"
  1. Check password encoding: If your password contains special characters (@, #, %), URL-encode them:

    • @ becomes %40
    • # becomes %23
  2. Check that your Supabase project is active. Free tier projects pause after 1 week of inactivity. Go to the Supabase dashboard and resume it.

  3. Run migrations against production:

DATABASE_URL="your-production-url" pnpm db:push

Domain not resolving

Symptom: Custom domain shows "DNS_PROBE_FINISHED_NXDOMAIN" or "This site can't be reached."

Cause: DNS records not configured or not yet propagated.

Fix:

  1. In Vercel, go to Settings > Domains and add your domain
  2. Vercel will show the DNS records you need to add:

For apex domain (e.g., yourdomain.com):

Type: A
Name: @
Value: 76.76.21.21

For subdomain (e.g., app.yourdomain.com):

Type: CNAME
Name: app
Value: cname.vercel-dns.com
  1. Add these records at your domain registrar (Namecheap, Cloudflare, GoDaddy, etc.)
  2. Wait for propagation — usually 5-30 minutes, but can take up to 48 hours

Check propagation status:

dig yourdomain.com A
  1. If using Cloudflare: Set the DNS proxy to "DNS only" (gray cloud), not "Proxied" (orange cloud). Vercel handles SSL and CDN.

Webhook URL not working in production

Symptom: Payments complete but webhooks aren't received. DodoPayments shows failed deliveries.

Cause: Webhook URL still pointing to localhost or an old domain.

Fix:

  1. Update the webhook URL in DodoPayments dashboard to:
https://yourdomain.com/api/webhook/dodo
  1. Make sure the URL uses HTTPS (not HTTP)

  2. Verify the route is accessible:

curl -X POST https://yourdomain.com/api/webhook/dodo \
  -H "Content-Type: application/json" \
  -d '{"test": true}'

You should get a response (even a 400 error about invalid signature means the route is reachable).

  1. Check that the webhook secret matches between your Vercel environment variables and DodoPayments dashboard.

"Function timeout" errors

Symptom: API routes return 504 Gateway Timeout on Vercel.

Cause: Route execution exceeds the timeout limit. Vercel Hobby plan: 10 seconds. Pro plan: 60 seconds.

Fix:

  1. Identify the slow operation. Add timing logs:
const start = Date.now();
const result = await slowOperation();
console.log(`Operation took ${Date.now() - start}ms`);
  1. Optimize database queries:

    • Add indexes for frequently queried columns
    • Use select() with specific columns instead of select()
    • Avoid N+1 queries — use joins
  2. Move heavy work to background jobs using Vercel Cron, Inngest, or Trigger.dev

  3. Use streaming for AI routes — the connection stays open but sends data incrementally, avoiding the timeout

  4. Upgrade to Vercel Pro if you need longer timeouts (60 seconds)

Static generation errors

Symptom: Build fails with "Error: Page ... couldn't be rendered statically."

Cause: A page that Next.js tries to pre-render uses dynamic data (cookies, headers, search params).

Fix:

Add dynamic rendering for pages that need runtime data:

export const dynamic = "force-dynamic";

Or if only specific parts need dynamic data, use unstable_noStore:

import { unstable_noStore as noStore } from "next/cache";

export default async function Page() {
  noStore();
  // ... fetch dynamic data
}

Preview deployments don't work

Symptom: Vercel preview deployments (for PRs) fail or have broken auth.

Cause: Preview URLs are dynamic, but auth callbacks and webhooks need a fixed URL.

Fix:

  1. For auth, set BETTER_AUTH_URL to the preview deployment URL, or use a wildcard:
# In Vercel env vars (Preview scope):
BETTER_AUTH_URL="https://*.vercel.app"

Note: OAuth providers need each preview URL added as a callback, which isn't practical. For preview deployments, test email/password auth instead of OAuth.

  1. For webhooks, preview deployments can't receive webhooks unless you configure a separate webhook URL for each preview. Most teams skip webhook testing in previews and test in staging.

  2. Use a separate database for preview deployments to avoid polluting production data.

Still stuck?

On this page