Vercel Deployment Checklist for Next.js
A pre-deployment checklist built from every broken Vercel deployment ShabelleHub has been through.
ShabelleHub has been through multiple Vercel deployments — some clean, some broken in ways that took time to diagnose. Each broken deployment taught us something specific. This is the deployment checklist we now follow before every push to main.
The Pre-Deployment Checklist
1. Environment Variables Are Set in Vercel
This is the most common cause of deployment failures for apps that work locally. Vercel's build environment does not have access to your local .env.local file. Every environment variable used in the app must be added to the Vercel project settings.
For ShabelleHub:
NEXT_PUBLIC_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY
SUPABASE_SERVICE_ROLE_KEY
NEXT_PUBLIC_ADSENSE_CLIENT_ID
RESEND_API_KEY
CONTACT_TO_EMAIL
Variables prefixed with NEXT_PUBLIC_ are available in the browser bundle. Variables without this prefix are server-only — available in API routes and getServerSideProps/getStaticProps but not in client code.
The check: if a page renders correctly locally but shows an error in production, missing environment variables are the first thing to look for.
2. The Service Role Key Is Never in Client Code
The SUPABASE_SERVICE_ROLE_KEY must not appear in any file accessible to the browser. ShabelleHub runs a prebuild check:
// package.json
{
"scripts": {
"prebuild": "node scripts/check-env-leakage.js",
"build": "next build"
}
}
If the check script finds the service role key referenced outside of lib/supabaseAdmin.js or pages/api/**, the build fails before Vercel even starts compiling. This prevents an accidental secret exposure from reaching production.
3. All Dependencies Are in package.json
Dependencies installed locally but not listed in package.json will not be available in Vercel's build environment. Vercel runs npm install from scratch using package.json and package-lock.json — it does not use your local node_modules.
The ShabelleHub incident that taught us this: framer-motion was removed from package.json during a cleanup but was still imported in two components. The build failed on Vercel with Module not found: Can't resolve 'framer-motion', while local builds worked because node_modules still contained the old installation.
The fix: npm install framer-motion followed by committing the updated package.json and package-lock.json.
4. There Are No TypeScript or ESLint Build Errors
Next.js fails the build on TypeScript errors and (depending on configuration) ESLint errors. Check locally before pushing:
npm run lint
npm run build
If the local build passes and the Vercel build fails, the environments have different Node.js versions or different environment variables — check both.
5. Dynamic Routes Have getStaticPaths or getServerSideProps
Every dynamic route ([slug].js, [id].js, [category].js) must either use getStaticPaths (for static generation) or getServerSideProps (for server-side rendering). A dynamic route without either will fail at build time.
For ShabelleHub's tool and blog post pages, getStaticPaths generates the list of valid slugs at build time. If a slug is not in the list and fallback: false is set, visiting that URL returns a 404.
Reading Vercel Build Logs
When a deployment fails, Vercel's build logs contain the exact error. The log is divided into phases:
Installing dependencies... ← npm install
Running prebuild... ← scripts.prebuild
Building... ← next build
Compiling...
Creating optimized build...
The error appears in the phase where it occurred. Common errors and their causes:
| Error | Cause |
|-------|-------|
| Module not found: Can't resolve 'X' | Package not in package.json |
| NEXT_PUBLIC_X is not defined | Environment variable missing in Vercel |
| Cannot read properties of undefined | Data fetching returned undefined — missing env var or API error |
| getStaticPaths returned undefined | getStaticPaths function missing a return statement |
| Build failed because of webpack errors | Import error or missing dependency |
The key habit: read the first error in the log. Subsequent errors are often cascading failures caused by the first. Fixing the first error frequently resolves all of them.
The Deployment Pipeline
ShabelleHub uses a simple trunk-based deployment flow:
- Make changes locally
- Test locally with
npm run dev - Run
npm run buildlocally to catch build errors before pushing - Push to the
mainbranch on GitHub - Vercel detects the push and starts a new deployment automatically
- Watch the Vercel dashboard for the deployment to complete
- Visit the production URL to verify the change
For larger changes, Vercel's preview deployments are useful — every branch push creates a unique preview URL that can be shared and tested before merging to main. ShabelleHub uses this for any change that modifies UI in a way that is difficult to verify from code alone.
Monitoring After Deployment
Three things to check after every deployment:
1. The Functions tab in Vercel. API routes appear as serverless functions. If any function is throwing errors, the Functions tab shows the error rate and recent log entries. For ShabelleHub, this catches issues with API routes that work locally but fail in the Vercel environment.
2. The PageSpeed score. Running the live URL through PageSpeed Insights after a significant change confirms that performance and SEO scores have not regressed. We saw the Performance score drop from 98 to 87 once after re-adding framer-motion animations — caught by the PageSpeed check after deployment.
3. The sitemap. Visiting /sitemap.xml on the live site confirms that new pages were generated and included in the sitemap. A missing page in the sitemap is a crawlability issue that is easy to catch and easy to miss.
The One Rule
Local builds that succeed do not guarantee Vercel builds will succeed. The environments differ in:
- Node.js version (Vercel uses the version specified in
package.json#enginesor its default) - Available environment variables
node_modulesstate (Vercel always does a clean install)- File system (Vercel's build is read-only after install; no writing to disk at build time)
The single most reliable check before pushing: run npm run build in a clean environment — delete node_modules, run npm install, then npm run build. If that passes, the Vercel build will pass.
On a mobile device with Termux, this means:
cd ~/shabellehub
rm -rf node_modules .next
npm install
npm run build
Time-consuming, but definitive. Run it before any deployment that has changed dependencies or environment variable usage.
*This article is part of the ShabelleHub Building in Public series.*
📬 Get the latest AI tool reviews
Expert picks and comparisons, weekly. No spam.