[▲ 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!