/ blog/debugging-ssr-runtime-crashes-vercel
blog / debugging-ssr-runtime-crashes-vercel / overview.md

Debugging SSR Runtime Crashes on Vercel: Node vs Edge

When your Next.js app works perfectly on localhost but throws 500s on Vercel. A deep dive into Node runtimes, the Edge network, and how to debug elusive server-side crashes.

The "Works on My Machine" Paradigm

Every Next.js developer knows the feeling. You run npm run dev. The site is snappy. The terminal shows no errors. You commit, push to main, and Vercel automatically deploys.

You click the production link: 500 Internal Server Error.

Server-Side Rendering (SSR) abstracts away the complexity of the server, but when it fails, it fails silently and obscurely. Here is a systematic approach to debugging production SSR crashes, based on the pain I went through migrating our platform.

1. The Environment Variable Trap

The number one cause of localhost vs. production divergence is environment variables.

In Next.js, variables prefixed with NEXT_PUBLIC_ are bundled into the client JavaScript. Everything else is securely kept on the server.

If your Server Component relies on SUPABASE_SERVICE_ROLE_KEY to fetch data, and you forgot to add it to Vercel's Environment Variables dashboard, the server fetch will fail. Because Server Components render on the server, a failed fetch often results in a total route crash.

The Fix: Always validate your environment variables at boot. We use Zod for this in a env.ts file:

import { z } from 'zod';

const envSchema = z.object({
  DATABASE_URL: z.string().url(),
  SUPABASE_SERVICE_ROLE_KEY: z.string().min(1),
  NEXT_PUBLIC_SITE_URL: z.string().url(),
});

export const env = envSchema.parse(process.env);

If a variable is missing, the build fails before it gets deployed.

2. The Node.js vs Edge Runtime Divide

Next.js offers two environments for your server code to execute in: the standard Node.js runtime, and the Edge runtime.

The Edge runtime is stripped down. It is V8 running in a heavily sandboxed environment designed to boot in milliseconds across global CDNs.

It does not support standard Node APIs. If your code uses fs, crypto, child_process, or depends on an npm package that does (like pg or bcrypt), it will crash on the Edge.

// This works in Node, crashes on Edge
import fs from 'fs';
const data = fs.readFileSync('./data.json', 'utf-8');

The Fix: Check your route.ts or page.tsx exports.

export const runtime = 'edge'; // Remove this if you need Node APIs!

If you must use Edge, you have to use Edge-compatible alternatives (e.g., using Web Crypto API instead of Node crypto).

3. Hydration Mismatches that trigger 500s

Usually, hydration errors (when the server HTML doesn't match the client HTML) just cause a nasty React warning in the console. But sometimes, they cause a complete crash.

This happens if your component renders conditionally based on something only the client knows, like window or localStorage.

export default function ThemeToggle() {
  // CRASH: window is undefined on the server!
  const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
  
  return <div>{isDark ? "Dark" : "Light"}</div>;
}

The Fix: Use an effect to delay client-specific rendering, or use CSS media queries.

export default function ThemeToggle() {
  const [isClient, setIsClient] = useState(false);
  
  useEffect(() => {
    setIsClient(true);
  }, []);

  if (!isClient) return <div className="fallback" />;
  
  return <div>{/* safe to use window here */}</div>;
}

4. Reading Vercel Runtime Logs

When you get a 500 error, you need to know where to look.

Vercel's log viewer is powerful, but you must know how to search it.

  1. Go to the Vercel Dashboard -> Your Project -> Logs.
  2. Filter by "Error".
  3. Look for the specific RequestId.

If you see Error: Cannot find module, it usually means a dependency was listed in devDependencies in your package.json, but was required by a production route. Vercel strips devDependencies before booting the production server.

Summary

Debugging SSR requires shifting your mindset. You are no longer just debugging a React app; you are debugging a distributed Node.js server.

  • Validate environment variables early.
  • Understand what runtime your code executes in.
  • Never trust window during the initial render.

Tags

devopsnextjsverceldebugging
0
0