Skip to content

Tanstack Start prerender broken with Nitro v3 on Vercel #3905

@josippapez

Description

@josippapez

Environment

Both nitro v3 and v2.
Node v24.12.0

Reproduction

Here's the reproducible:
https://github.com/josippapez/tanstack-vercel-reproducible

Describe the bug

I get the following error:

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/my-app/.output/server/server.js' imported from /my-app/node_modules/.pnpm/@tanstack+start-plugin-core@1.141.5_@tanstack+react-router@1.141.4_react-dom@19.2.3_rea_8f07dd2dc4f2e030cbea330a30ef30f3/node_modules/@tanstack/start-plugin-core/dist/esm/preview-server-plugin/plugin.js
    at finalizeResolution (node:internal/modules/esm/resolve:274:11)
    at moduleResolve (node:internal/modules/esm/resolve:864:10)
    at defaultResolve (node:internal/modules/esm/resolve:990:11)
    at nextResolve (node:internal/modules/esm/hooks:785:28)
    at o (file:///my-app/node_modules/.pnpm/@tailwindcss+node@4.1.18/node_modules/@tailwindcss/node/dist/esm-cache.loader.mjs:1:69)
    at nextResolve (node:internal/modules/esm/hooks:785:28)
    at AsyncLoaderHooksOnLoaderHookWorker.resolve (node:internal/modules/esm/hooks:271:30)
    at MessagePort.handleMessage (node:internal/modules/esm/worker:251:24)
    at [nodejs.internal.kHybridDispatch] (node:internal/event_target:845:20)
    at MessagePort.<anonymous> (node:internal/per_context/messageport:23:28)

For this vite.config.ts

import { defineConfig } from 'vite';
import { tanstackStart } from '@tanstack/react-start/plugin/vite';
import viteReact from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
import tailwindcss from '@tailwindcss/vite';
import { nitro } from 'nitro/vite';

const config = defineConfig({
  build: {
    sourcemap: true,
    outDir: '.output',
    emptyOutDir: true,
    target: 'es2022',
    minify: true,
    rollupOptions: {
      treeshake: true,
      output: {
        manualChunks: (id: string) => {
          if (
            id.includes('phone/dist') ||
            id.includes('react-phone-number-input')
          ) {
            return 'phone';
          }

          if (id.includes('lodash')) {
            return 'lodash';
          }

          if (id.includes('country-flag-icons')) {
            return 'country-flag-icons';
          }

          if (id.includes('medusa')) {
            return 'medusa';
          }
        },
      },
    },
  },
  plugins: [
    // this is the plugin that enables path aliases
    viteTsConfigPaths({
      projects: ['./tsconfig.json'],
    }),
    tailwindcss(),
    tanstackStart(),
    nitro({
      preset: 'vercel',
      output: {
        dir: '.output',
        serverDir: '.output/server',
        publicDir: '.output/static',
      },
      routeRules: {
        // Cache fonts for 1 year (immutable)
        '/fonts/**': {
          headers: {
            'Cache-Control': 'public, max-age=31536000, immutable',
          },
        },
        // Cache images for 1 month
        '/**/*.{jpg,jpeg,png,gif,webp,svg,ico}': {
          headers: {
            'Cache-Control': 'public, max-age=2592000',
          },
        },
        // cache css
        '/**/*.{css}': {
          headers: {
            'Cache-Control': 'public, max-age=604800',
          },
        },
      },
    }),
    viteReact(),
  ],
  resolve: {
    alias: {
      '/fonts': '/public/fonts',
    },
  },
  ssr: {
    noExternal: ['@radix-ui/*', '@medusajs/*', 'nuqs'],
  },
});

export default config;

I did try invoking server.js/index.mjs directly with pnpm serve and node .output/server/index.mjs.

and then i try to pnpm dev (works), pnpm build passes and then pnpm preview and node index.mjs directly, and the node one doesn't start while the preview returns the same error as above

Additional context

No response

Logs

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions