Express + Next.js route ownership
The routing contract that prevents self-proxy loops and keeps the School-GIT public origin unified.
System flow
Request hits :3000
Express checks owned route
Otherwise proxy to :3001
Next resolves route locally
Source map
- server.js
- next.config.js
- app/api/cdn/*
Architecture diagram
mermaidflowchart TD
A[Incoming request :3000] --> B{Express-owned?}
B -->|yes| C[Handle in server.js]
B -->|no| D[Proxy to Next :3001]
D --> E{Next route exists?}
E -->|yes| F[Handle in Next]
E -->|no| G[Next 404]
F -. never rewrite Next-owned API back to :3000 .-> FAuthoritative ownership
The routing model works when each path has a single owner. Express should directly handle its legacy/host/runtime endpoints, while the Web Bro and OS APIs remain inside Next.js.
- /api/cdn/execute โ Express.
- /api/cdn/files โ Express.
- /api/cdn/logs โ Express.
- /api/cdn/container-status โ Express.
- /api/cdn/profile โ Express.
- /api/cdn/apps/* โ Next.js.
- /api/cdn/os/* โ Next.js.
The proxy-loop failure mode
If Express proxies /api/cdn/apps/* to Next, but next.config.js rewrites generic /api/cdn/* traffic back to Express, the same request can bounce between :3000 and :3001 until it times out or resets.
The fix is not to proxy Next-owned routes back to port 3000. Keep rewrites narrowly scoped to explicit Express-owned endpoints.
text// Good mental model
Express :3000
โโ /api/cdn/execute -> handle here
โโ /api/cdn/files -> handle here
โโ /api/cdn/apps/* -> proxy once to Next :3001
Next :3001
โโ /api/cdn/apps/* -> handle here, no rewrite back to :3000Debugging ownership
Test the Next port directly first, then test the public Express port. If the Next request succeeds and the public request hangs, the problem is usually proxy ownership or forwarding rather than the route implementation itself.