🚀 Executive Summary

TL;DR: Next.js images often 404 on Vercel CLI deployments because the default process doesn’t upload the locally built .next folder containing optimized images. The solution involves using the `vercel deploy –prebuilt` flag or configuring `vercel.json` to ensure the pre-built output is recognized and deployed.

🎯 Key Takeaways

  • Vercel CLI deployments, by default, only upload source code, omitting the crucial `.next` build output folder where Next.js optimized images reside.
  • GitHub-triggered Vercel deployments succeed because Vercel performs a full `next build` on its servers, generating all assets, including optimized images, in the correct context.
  • The `–prebuilt` flag is the primary fix for Vercel CLI 404s, instructing Vercel to deploy the locally pre-built `.next` directory directly, ensuring optimized images are included.

Next Image imgs 404 when vercel-cli deploying, but work fine when deploying via github repo

Struggling with Next.js image 404s when deploying via the Vercel CLI? The issue is a mismatch in build context; the fix involves telling Vercel to use your pre-built local output.

So, Your Next.js Images 404 on Vercel CLI Deploys? Let’s Talk.

I remember it clear as day. 10:30 PM on a Tuesday. We were pushing a critical hotfix for a new marketing lander. The staging deployment, triggered from a GitHub merge, looked perfect. All the slick, optimized Next.js images were loading faster than our morning coffee order. Then came the production push using vercel --prod. I hit enter, the deployment finished, and my blood ran cold. Every single <Image> component was a sad, broken 404 icon. The site was live, the client was watching, and our beautiful UI looked like a ghost town. If this sounds familiar, you’re not alone, and the fix is thankfully less painful than that memory.

The “Why”: It’s Not You, It’s the Build Context

This is a classic “It works on my machine!” problem, but with a cloud-native twist. The root cause is a fundamental difference in how Vercel builds your project based on the deployment method.

GitHub Deployment (The “It Works” Way) Vercel CLI Deployment (The “It Breaks” Way)
Vercel pulls your source code from the repository. It then runs the build command (next build) on its own servers, inside its own clean environment. It generates the optimized images, the serverless functions, and all the static assets right there. Everything it needs is in one place. By default, vercel deploy zips up the source code in your current local directory and uploads it. It does not include the local .next build output folder unless you explicitly tell it to. Vercel then tries to run the build on its side, but the context is different, and crucially, the pre-optimized images from your local build aren’t there.

So, your local build creates those perfectly optimized WebP images in .next/static/image, but the default CLI command doesn’t send that folder up. The result? 404s everywhere.

The Fixes: From Quick Patch to Proper Solution

Alright, enough theory. You’re here because something is on fire. Here’s how we put it out, starting with the fastest fix.

1. The Quick Fix: The `–prebuilt` Flag

This is your emergency lever. If you need the site fixed right now, this is the command to use. It tells Vercel, “Don’t bother trying to build this yourself. I’ve already run next build locally. Just take my finished .next folder and serve it.”

First, make sure you have a fresh build:

npm run build

Then, deploy using the magic flag:

vercel deploy --prebuilt --prod

This command will grab your local build output, including the optimized images, and deploy it directly. Your 404s will vanish. It’s fast, effective, and perfect for hotfixes or CI/CD pipelines where you control the build step.

Pro Tip: Using --prebuilt is the standard way to handle deployments from a CI/CD environment like Jenkins or GitHub Actions. You run your tests, build the artifact (the .next folder), and then the final step is just shipping that pre-built artifact to Vercel.

2. The Permanent Fix: Configure `vercel.json`

Relying on a command-line flag is fine, but it’s not foolproof. A teammate might forget it. A new script might miss it. The more robust solution is to tell Vercel how to handle your project structure directly in your vercel.json file.

You can define the “output directory” for your project. When Vercel sees this, it knows where to find the static assets after its own build process. For a standard Next.js project, this isn’t usually necessary, but it helps clarify the project type. The more important configuration is ensuring your build commands are right.

A properly configured vercel.json for a Next.js app often just relies on the framework detection. But if you’re running into CLI issues, it’s good practice to have one. The key is ensuring your Vercel project settings (in the web UI) are correctly set to “Next.js” as the framework. If it’s not, Vercel won’t know to run next build and handle the output correctly.

If you’re still facing issues, you can explicitly define the build:

{
  "builds": [
    {
      "src": "next.config.js",
      "use": "@vercel/next"
    }
  ]
}

This explicitly tells Vercel to use its Next.js builder. Combine this with setting the framework preset in the Vercel dashboard, and Vercel’s CLI-triggered builds will behave just like the Git-triggered ones, solving the problem at the source.

3. The ‘Nuclear’ Option: Manually Copying Files

Look, I’m going to be honest with you. This is a hack. It’s messy. It bypasses some of the magic of Next.js Image Optimization. But I’m including it because I’ve seen edge cases with monorepos or bizarre project structures where this was the only thing that got a team unstuck before a deadline.

The idea is to change your build process to manually copy the generated images from the .next/static/ directory into the public/ directory. Anything in public/ gets served as a static asset from the root. This is a brute-force approach.

Modify your package.json scripts:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "build:vercel": "next build && cp -R .next/static/media public/static/media"
  }
}

Warning: I cannot stress this enough. This is a last resort. It can increase your build times, make your slug size larger, and you lose some of the on-demand optimization benefits. Only use this if the other two options have failed and you have a very, very good reason.

Ultimately, the culprit is almost always the context difference. Stick with the --prebuilt flag for your CI/CD and manual deploys. It’s the cleanest, most idiomatic way to tell Vercel, “I’ve got this handled.” Your late-night self will thank you.

Darian Vance - Lead Cloud Architect

Darian Vance

Lead Cloud Architect & DevOps Strategist

With over 12 years in system architecture and automation, Darian specializes in simplifying complex cloud infrastructures. An advocate for open-source solutions, he founded TechResolve to provide engineers with actionable, battle-tested troubleshooting guides and robust software alternatives.


🤖 Frequently Asked Questions

âť“ Why do Next.js images result in 404 errors when deploying via Vercel CLI but not via GitHub?

Vercel CLI’s default behavior uploads only source code, excluding the locally generated `.next` build output containing optimized images. GitHub deployments trigger a full build on Vercel’s servers, which correctly generates and includes these assets.

âť“ How do the `–prebuilt` flag and `vercel.json` configuration compare as solutions?

The `–prebuilt` flag is a quick, effective fix for immediate deployments or CI/CD by deploying your local `.next` output. Configuring `vercel.json` provides a more robust, permanent solution by explicitly defining the build process for Vercel.

âť“ What is a common implementation pitfall when deploying Next.js projects with images to Vercel via CLI?

A common pitfall is failing to account for the build context difference, specifically not using the `–prebuilt` flag or ensuring `vercel.json` is configured to properly handle the Next.js build output, leading to missing optimized images and 404 errors.

Leave a Reply

Discover more from TechResolve - SaaS Troubleshooting & Software Alternatives

Subscribe now to keep reading and get access to the full archive.

Continue reading