[▲ Vercel Community](/) · [Categories](/categories) · [Latest](/latest) · [Top](/top) · [Live](/live) [Help](/c/help/9) # Next.js SSR build fails due to pageExtension issues 78 views · 0 likes · 3 posts Gutscdav000 (@gutscdav000) · 2025-07-03 # Hybrid Next.js App: Static + SSR + API Routes – "Catch 22" with Vercel, `.api.ts` Suffix, and Static Export My SSR/default vercel builds are failing, seemingly because I have named my route files with a `.api.ts` suffix. I include this in my `pageExtensions` for my default build, and exclude them from my static build where my client pages call the endpoints from the SSR build. This is required for my static capacitor build. ## **Project Context** - **Framework:** Next.js `15.2.4` - **Deployment:** Vercel (builds triggered on push to a branch) - **Environment:** All required environment variables are defined in Vercel - **Static Build:** Exists to support a Capacitor-based mobile app (using `output: 'export'`) - **SSR Build:** Standard Vercel SSR deployment for web - **API Routes:** Many dynamic endpoints under `src/app/api` --- ## **Relevant File Structure** ``` src/app/api/ ├── auth/ │ └── reset-password/ │ └── route.api.ts ├── calendly/ │ ├── callback/ │ │ └── route.api.ts │ ├── end-of-day/ │ │ └── route.api.ts │ ├── profile/ │ │ └── route.api.ts │ ├── reset/ │ │ └── route.api.ts │ ├── route.api.ts │ └── status/ │ └── route.api.ts ├── jobs/ │ ├── dequeueLeads/ │ │ └── route.api.ts │ └── updateAvailability/ │ └── route.api.ts ├── leads/ │ └── [userId]/ │ └── route.api.ts ├── login/ │ └── route.api.ts ├── onboarding/ │ └── route.api.ts ├── queue/ │ ├── cron/ │ │ └── route.api.ts │ ├── increment/ │ │ └── route.api.ts │ ├── push/ │ │ └── route.api.ts │ ├── recently-contacted/ │ │ └── [userId]/ │ │ └── route.api.ts │ ├── status/ │ │ └── route.api.ts │ └── [userId]/ │ └── route.api.ts └── user/ ├── cover-photo/ │ └── route.api.ts ├── route.api.ts └── search/ └── route.api.ts ``` --- ## **Build Configuration (`next.config.mjs`)** ```js // Configuration for Capacitor (static export) const capacitorConfig = { output: 'export', reactStrictMode: true, images: { unoptimized: true }, pageExtensions: ['tsx', 'ts', 'jsx', 'js'], distDir: 'out', }; // Default configuration for SSR/Serverful deployments const defaultConfig = { reactStrictMode: true, images: { unoptimized: false }, pageExtensions: ['tsx', 'ts', 'jsx', 'js', 'api.ts', 'web.tsx'], }; const isCapacitorBuild = process.env.NEXT_PUBLIC_BUILD_TARGET === 'capacitor'; export default isCapacitorBuild ? capacitorConfig : defaultConfig; ``` - **Intent:** - For SSR: Include `.api.ts` so API routes are available. - For static export: Exclude `.api.ts` so API routes are not included (since static build cannot support them). - **Note:** The static build is used by the Capacitor mobile app, which calls the SSR endpoints deployed on Vercel. --- ## **The Catch-22** ### **If I use `.api.ts` for API routes:** - **SSR build works locally** (API routes included). - **Static build works locally** (API routes excluded). - **But on Vercel, the SSR/default build faiIs with this error:** ``` Traced Next.js server files in: 60.047ms Error: ENOENT: no such file or directory, lstat '/vercel/path0/.next/server/app/api/calendly/callback/route_client-reference-manifest.js' Exiting build container ``` - This seems to be because Vercel expects a `route.ts` for every route reference, and the exclusion via `pageExtensions` causes a mismatch. Meanwhile I'm providing a `route.api.ts` and including this file suffix: `.api.ts` in my pageExtensions. ### **If I use `route.ts` for API routes and try to force static:** - Adding `export const dynamic = "force-static";` or similar does not work for dynamic API endpoints. - **Static build fails with errors like:** ``` Error occurred prerendering page "/api/calendly". Error: Route /api/calendly with `dynamic = "error"` couldn't be rendered statically because it used `request.url`. Export encountered an error on /api/calendly/route: /api/calendly, exiting the build. ``` - **Why?** - Many API endpoints (e.g., `/api/calendly/callback`) are fundamentally dynamic: they need to handle OAuth callbacks, parse query params, and use `request.url` at runtime. - Static export cannot support these, and Next.js throws errors if you try. --- ## **Example: Why Static Routing Won't Work (Calendly Callback)** - The endpoint `/api/calendly/callback/route.ts` handles OAuth callbacks from Calendly. - It must: - Parse the incoming request's URL and query parameters. - Handle dynamic, user-specific, and time-sensitive data. - **Static export cannot possibly pre-generate all possible callback URLs or handle dynamic runtime data.** - Forcing this route to be static results in build errors, as Next.js cannot resolve the dynamic logic at build time. --- ## **Summary of the Problem** - **I need both SSR (with API routes) and a static build (for Capacitor/mobile).** - **Excluding API routes via file extension works locally, but fails on Vercel.** - **Forcing API routes to be static is not possible due to their dynamic nature.** - **There seems to be no clean way to have a hybrid Next.js app with both SSR API routes and a static export for mobile, using a single codebase and Vercel.** --- ## **What I'm Looking For** - **Is there a best-practice way to structure a Next.js project to support both SSR (with API routes) and a static export (for Capacitor/mobile) on Vercel?** - **How can I avoid the ENOENT error on Vercel when excluding API routes from the static build?** - **Is there a recommended pattern for hybrid SSR/static + API route projects, or is a monorepo/separate app approach the only way?** --- **Any advice, workarounds, or pointers to official guidance would be greatly appreciated!** The only idea I've had is writing a script to use for generating my static build that moves the api folder out of the app folder, then moves it back after the build runs. I bet this would work, but boy is it a hack I'd rather avoid. Jacob Paris (@jacobparis) · 2025-07-04 The architecture you need here is - static site that can be packaged with Capacitor - hosted API routes Vercel supports API routes that are outside of Next.js but still in the same codebase, you'll just need to move your /app/api routes into top level route handlers at /api If you follow directions for "Other frameworks" here it should show you the way https://vercel.com/docs/functions?framework=other system (@system) · 2026-01-20 Hi @gutscdav000! 🔔 This thread's been quiet for a while. If you're still facing issues, please share any relevant details (logs, screenshots, error messages) so we can take another look!