Next.js App Deployment Issue - 404 NOT_FOUND

Next.js Quiz App Deployment Issue - 404 NOT_FOUND

I’m experiencing a 404 error when trying to access my deployed Next.js quiz application at:

The error code is NOT_FOUND with ID: lhr1::hh7lj-1744278809623-d5fbec10eb90.

Project Details

  • Framework: Next.js 14.1.0

  • Build Command: pnpm run build

  • Output Directory: .next

  • Node.js Version: 18.x

Project Structure

├── app/

│ ├── layout.tsx

│ ├── page.tsx

│ └── globals.css

├── components/

│ ├── quiz-app.tsx

│ ├── quiz-question.tsx

│ ├── user-statistics.tsx

│ └── lazy-components.tsx

├── lib/

│ └── db.ts

├── types/

│ └── question-types.ts

└── data/

└── question-bank.ts

Configuration Files

next.config.mjs

/** @type {import('next').NextConfig} */
const nextConfig = {
  eslint: {
    ignoreDuringBuilds: false,
  },
  typescript: {
    ignoreBuildErrors: false,
  },
  images: {
    unoptimized: true,
    domains: ['game.stutern.africa'],
  },
  experimental: {
    webpackBuildWorker: true,
    parallelServerBuildTraces: true,
    parallelServerCompiles: true,
  },
  output: 'standalone',
  poweredByHeader: false,
  reactStrictMode: true,
  swcMinify: true,
  async headers() {
    return [
      {
        source: '/(.*)',
        headers: [
          {
            key: 'X-Forwarded-Proto',
            value: 'https',
          },
          {
            key: 'X-Frame-Options',
            value: 'DENY',
          },
          {
            key: 'X-Content-Type-Options',
            value: 'nosniff',
          },
          {
            key: 'Referrer-Policy',
            value: 'strict-origin-when-cross-origin',
          },
        ],
      },
    ];
  },
  async rewrites() {
    return [
      {
        source: '/',
        destination: '/',
      },
      {
        source: '/:path*',
        destination: '/:path*',
      },
    ];
  },
};

vercel.json

{
  "rewrites": [
    {
      "source": "/(.*)",
      "destination": "/"
    }
  ]
}

Environment Variables

  • NEXT_PUBLIC_BASE_URL=https://game.stutern.africa
  • POSTGRES_URL (configured with PostgreSQL connection string)

Build Output

The build completes successfully with the following routes:

  • / (24.5 kB)
  • /_not-found (888 B)
  • /api/leaderboard (0 B)
  • /api/test-base-url (0 B)

Issue

Despite successful builds and proper configuration, accessing the deployed application results in a 404 error. The application works correctly in development mode.

Troubleshooting Steps Taken

  1. Verified build output and routes
  2. Checked Next.js configuration
  3. Added Vercel-specific rewrite rules
  4. Confirmed environment variables are properly set
  5. Verified the root page component exists and exports correctly

Additional Context

  • The application is a quiz app with multiple-choice questions
  • Uses PostgreSQL for data storage
  • Implements lazy loading for components
  • Has proper TypeScript configurations
  • Uses Tailwind CSS for styling

Any assistance in resolving this deployment issue would be greatly appreciated. Thank you!

There’s another community post with 404 debugging tips that might be helpful. Please give these solutions a try and let us know how it goes.

A human should be around soon to offer more advice. But you can also get helpful information quickly by asking v0.

Hey, @kehindeayan! Welcome to the Vercel Community :waving_hand:

Did you take a look at our resource above? :folded_hands:

Let us know how you get on!

Hi @pawlean, thank you for the warm welcome! :waving_hand:

I’ve reviewed the RESOURCE_NOT_FOUND documentation and tried the recommended troubleshooting steps:

  1. Resource Existence: Verified that all necessary files exist in the correct locations
  2. Access Permissions: Confirmed that the application has the required permissions
  3. Resource Path: Double-checked all paths in the configuration files
  4. Application Configuration: Reviewed both next.config.mjs and vercel.json
  5. Logs: Checked the build logs which show successful compilation

Here’s what I’ve found:

  • The build completes successfully with all routes generated
  • The application works perfectly in development mode
  • The deployment process completes without errors
  • The 404 error only occurs when accessing the production URL and custom domain

I’ve also tried:

  • Clearing the Next.js cache
  • Rebuilding the project
  • Verifying environment variables
  • Checking the rewrite rules in both configuration files

Could you help me understand if there might be any specific Vercel deployment settings I should check? Or if there are any known issues with Next.js 14.1.0 deployments that might cause this behavior?

Thank you for your assistance!

Hi @kehindeayan, from the build output it looks like your project is not configured to use Next.js framework presets. Can you go to the Project Settings > Build and Deployment and confirm that?

Also, can you share why you have the rewrites with the same source and destination?

1 Like

Thank you @anshumanb

It looks exactly like this [pls see img below]. Am I missing anything? :slight_smile:

Hi @kehindeayan, I see. Thanks for sharing.

Can you share the next.config.js or next.config.mjs files here?

Yes, please @anshumanb

Here’s the current next.config.js configuration file:

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  // Only use basePath in production
  basePath: process.env.NODE_ENV === 'production' ? '/game' : '',
  assetPrefix: process.env.NODE_ENV === 'production' ? 'https://game.stutern.africa/' : undefined,
  images: {
    domains: ['stutern.africa'],
  },
  async rewrites() {
    // Only apply rewrites in production
    if (process.env.NODE_ENV === 'production') {
      return [
        {
          source: '/game/:path*',
          destination: '/:path*',
        },
      ]
    }
    return []
  },
}

module.exports = nextConfig



And here’s the next.config.mjs configuration file:

import { getConfig } from '@vercel/next'

let userConfig = undefined
try {
  // try to import ESM first
  userConfig = await import('./v0-user-next.config.mjs')
} catch (e) {
  try {
    // fallback to CJS import
    userConfig = await import("./v0-user-next.config");
  } catch (innerError) {
    // ignore error
  }
}

/** @type {import('next').NextConfig} */
const nextConfig = {
  eslint: {
    ignoreDuringBuilds: false,
  },
  typescript: {
    ignoreBuildErrors: false,
  },
  images: {
    unoptimized: true,
    domains: ['game.stutern.africa'],
  },
  experimental: {
    webpackBuildWorker: true,
    parallelServerBuildTraces: true,
    parallelServerCompiles: true,
  },
  output: 'standalone',
  poweredByHeader: false,
  reactStrictMode: true,
  swcMinify: true,
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'X-Forwarded-Proto',
            value: 'https',
          },
          {
            key: 'X-Frame-Options',
            value: 'DENY',
          },
          {
            key: 'X-Content-Type-Options',
            value: 'nosniff',
          },
          {
            key: 'Referrer-Policy',
            value: 'strict-origin-when-cross-origin',
          },
          {
            key: 'Permissions-Policy',
            value: 'camera=(), microphone=(), geolocation=()',
          },
          {
            key: 'Content-Security-Policy',
            value: "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;",
          },
        ],
      },
    ]
  },
  async rewrites() {
    return [
      {
        source: '/',
        destination: '/',
      },
      {
        source: '/:path*',
        destination: '/:path*',
      },
    ]
  },
  async redirects() {
    return [
      {
        source: '/api/:path*',
        destination: '/api/:path*',
        permanent: false,
      },
    ]
  },
}

if (userConfig) {
  // ESM imports will have a "default" property
  const config = userConfig.default || userConfig

  for (const key in config) {
    if (
      typeof nextConfig[key] === 'object' &&
      !Array.isArray(nextConfig[key])
    ) {
      nextConfig[key] = {
        ...nextConfig[key],
        ...config[key],
      }
    } else {
      nextConfig[key] = config[key]
    }
  }
}

export default nextConfig

HI @kehindeayan, it looks like I can access your website on Quiz Game because the basePath is set to /game in production.

There is nothing hosted on the / path as of now because the / of your app is /game. Hence, the 404.

2 Likes

Thank you so much for pointing that out! You’re absolutely right.

The 404 mystery is solved! Everything is running smoothly now. You made my day @anshumanb! 12 hours of toiling is over!! I can finally call it a day! :raising_hands: No more pesky 404s. :sweat_smile:

Thanks again for your help, you’re a lifesaver.

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.