Fresh 2.x basePath: Root Route Not Mapped Correctly
Summary
Hi all, i'm running into an issue where App({ basePath }) in Fresh 2.x doesn't correctly map the root route (routes/index.tsx) to the basePath location. Everything else works - nested routes, API routes, static assets - but hitting the root path returns a 404.
Environment
- Fresh version:
jsr:@fresh/core@^2.1.4
- Deno version:
2.5.6 (stable, release, x86_64-unknown-linux-gnu)
- V8:
14.0.365.5-rusty
- TypeScript:
5.9.2
- OS: Linux (Debian)
- Deployment: nginx reverse proxy forwarding to Fresh app
Use Case
Running Fresh application behind nginx reverse proxy at a custom subpath for multi-app deployment:
- nginx proxy:
https://example.com/apps/myapp/ → http://10.64.2.211:8081/apps/myapp/
- nginx preserves full path (no rewrite)
- Fresh configured with
basePath: "/apps/myapp"
Expected Behavior
With basePath: "/apps/myapp" set, all routes should be accessible under the basePath prefix:
GET /apps/myapp/ → should route to routes/index.tsx
GET /apps/myapp/d/123/doc → should route to routes/d/[uuid]/[[slug]].tsx
GET /apps/myapp/api/spaces → should route to routes/api/spaces.ts
Actual Behavior
With basePath: "/apps/myapp" set:
GET /apps/myapp/ → 404 - Route not found (FAILS)
GET /apps/myapp/d/123/doc → works correctly
GET /apps/myapp/api/spaces → works correctly
Only the root route fails; all nested routes work as expected.
Reproduction
1. Fresh App Configuration
main.ts:
import { App, staticFiles } from "fresh";
const basePath = Deno.env.get("BASE_PATH") || "";
export const app = new App<State>({
basePath,
});
app.use(staticFiles());
app.fsRoutes();
routes/index.tsx:
import { define } from "../utils.ts";
export const handler = define.handlers({
async GET(ctx) {
// Route logic here
return { data: { message: "Home page" } };
},
});
export default define.page(function Home(props) {
return <div>Welcome</div>;
});
Environment:
BASE_PATH="/apps/myapp"
SERVER_PORT="8081"
2. nginx Configuration
Setup:
- Domain
dev.docillo.com configured with Custom Location
- Location
/apps/docs/ forwarded to Fresh app at http://10.64.2.211:8081
Proxy configuration:
# Custom Location: /apps/docs/
location /apps/docs/ {
proxy_pass http://10.64.2.211:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Key points:
- No path stripping/rewriting in nginx
- nginx forwards
/apps/docs/ as-is to Fresh app running on 10.64.2.211:8081
- Fresh receives the full path including basePath
3. Steps to Reproduce
- Set up Fresh app with basePath configuration as shown above
- Create
routes/index.tsx with a simple handler
- Create nested route like
routes/d/[uuid]/[[slug]].tsx
- Configure nginx to forward
/apps/myapp/* to Fresh app
- Start Fresh app with
BASE_PATH="/apps/myapp"
- Access routes:
https://example.com/apps/myapp/ → 404
https://example.com/apps/myapp/d/test-uuid/doc → works
Evidence
Server Logs
Fresh startup confirms basePath is configured:
🚀 SERVER STARTING
Version: 0.2.0
Environment: development
Port: 8081
[Bootstrap] Routes mounted with basePath: /apps/myapp
[App] Fresh app v0.2.0 platform ready
Request to root returns 404:
[Middleware] GET /apps/myapp/
[Middleware] 404 - Route not found: /apps/myapp/
Nested routes work correctly:
[Middleware] GET /apps/myapp/d/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d/doc
[Middleware] Route access: /apps/myapp/d/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d/doc
Middleware Investigation
Middleware confirms route matching failure for basePath root:
export default define.middleware(async (ctx) => {
const url = new URL(ctx.req.url);
const pathname = url.pathname;
if (ctx.route === null) {
debug(`404 - Route not found: ${pathname}`);
return await ctx.next();
}
debug(`Route access: ${pathname}`);
return await ctx.next();
});
Result:
/apps/myapp/ → ctx.route === null (FAILS)
/apps/myapp/d/... → ctx.route !== null (works)
/apps/myapp/api/... → ctx.route !== null (works)
Analysis
The basePath configuration is successfully applied to:
- Static assets (served under
/apps/myapp/assets/*)
- Nested file routes (
routes/d/[uuid]/... → /apps/myapp/d/...)
- API routes (
routes/api/... → /apps/myapp/api/...)
But fails for:
- Root route (
routes/index.tsx → /apps/myapp/)
This suggests that App({ basePath }) correctly prefixes nested routes discovered by app.fsRoutes(), but the special case of the root route (index.tsx → "/") is not being mapped to basePath + "/".
Impact
This issue prevents Fresh applications from being deployed at custom subpaths via reverse proxy when the root route needs to be accessible. It forces developers to either:
- Not use custom basePaths
- Implement manual route workarounds
- Deploy each Fresh app at its own domain
Additional Context
- Direct access without basePath works:
http://localhost:8081/ routes correctly to routes/index.tsx
- The issue only manifests when
basePath is non-empty
- Assets and nested routes respect basePath correctly
- Trailing slash behavior confirmed: both
/apps/myapp and /apps/myapp/ return 404
Related
Similar issues may have been reported regarding basePath support in Fresh 2.x. This appears to be a gap in how the root route is registered when basePath is set.
Expected Fix:
When App({ basePath: "/apps/myapp" }) is configured and app.fsRoutes() is called, the root route from routes/index.tsx should be mapped to /apps/myapp/ just as nested routes are correctly mapped under the basePath prefix.
Just wanted to say thanks for all the work on Fresh. This is my first web framework and I'm really enjoying working with it - building some cool stuff for myself and my workplace. Despite running into this issue, the overall experience has been great. Keep up the excellent work!
Fresh 2.x basePath: Root Route Not Mapped Correctly
Summary
Hi all, i'm running into an issue where
App({ basePath })in Fresh 2.x doesn't correctly map the root route (routes/index.tsx) to the basePath location. Everything else works - nested routes, API routes, static assets - but hitting the root path returns a 404.Environment
jsr:@fresh/core@^2.1.42.5.6(stable, release, x86_64-unknown-linux-gnu)14.0.365.5-rusty5.9.2Use Case
Running Fresh application behind nginx reverse proxy at a custom subpath for multi-app deployment:
https://example.com/apps/myapp/→http://10.64.2.211:8081/apps/myapp/basePath: "/apps/myapp"Expected Behavior
With
basePath: "/apps/myapp"set, all routes should be accessible under the basePath prefix:GET /apps/myapp/→ should route toroutes/index.tsxGET /apps/myapp/d/123/doc→ should route toroutes/d/[uuid]/[[slug]].tsxGET /apps/myapp/api/spaces→ should route toroutes/api/spaces.tsActual Behavior
With
basePath: "/apps/myapp"set:GET /apps/myapp/→ 404 - Route not found (FAILS)GET /apps/myapp/d/123/doc→ works correctlyGET /apps/myapp/api/spaces→ works correctlyOnly the root route fails; all nested routes work as expected.
Reproduction
1. Fresh App Configuration
main.ts:
routes/index.tsx:
Environment:
2. nginx Configuration
Setup:
dev.docillo.comconfigured with Custom Location/apps/docs/forwarded to Fresh app athttp://10.64.2.211:8081Proxy configuration:
Key points:
/apps/docs/as-is to Fresh app running on10.64.2.211:80813. Steps to Reproduce
routes/index.tsxwith a simple handlerroutes/d/[uuid]/[[slug]].tsx/apps/myapp/*to Fresh appBASE_PATH="/apps/myapp"https://example.com/apps/myapp/→ 404https://example.com/apps/myapp/d/test-uuid/doc→ worksEvidence
Server Logs
Fresh startup confirms basePath is configured:
Request to root returns 404:
Nested routes work correctly:
Middleware Investigation
Middleware confirms route matching failure for basePath root:
Result:
/apps/myapp/→ctx.route === null(FAILS)/apps/myapp/d/...→ctx.route !== null(works)/apps/myapp/api/...→ctx.route !== null(works)Analysis
The basePath configuration is successfully applied to:
/apps/myapp/assets/*)routes/d/[uuid]/...→/apps/myapp/d/...)routes/api/...→/apps/myapp/api/...)But fails for:
routes/index.tsx→/apps/myapp/)This suggests that
App({ basePath })correctly prefixes nested routes discovered byapp.fsRoutes(), but the special case of the root route (index.tsx → "/") is not being mapped tobasePath + "/".Impact
This issue prevents Fresh applications from being deployed at custom subpaths via reverse proxy when the root route needs to be accessible. It forces developers to either:
Additional Context
http://localhost:8081/routes correctly toroutes/index.tsxbasePathis non-empty/apps/myappand/apps/myapp/return 404Related
Similar issues may have been reported regarding basePath support in Fresh 2.x. This appears to be a gap in how the root route is registered when basePath is set.
Expected Fix:
When
App({ basePath: "/apps/myapp" })is configured andapp.fsRoutes()is called, the root route fromroutes/index.tsxshould be mapped to/apps/myapp/just as nested routes are correctly mapped under the basePath prefix.Just wanted to say thanks for all the work on Fresh. This is my first web framework and I'm really enjoying working with it - building some cool stuff for myself and my workplace. Despite running into this issue, the overall experience has been great. Keep up the excellent work!