App-Directory File Routing
Relevant source files
The following files were used as context for generating this wiki page:
App-Directory File Routing provides a file-system based routing system for the Farm.js framework. It maps directories and specific file naming conventions within the src/app directory directly to URL paths in the application. This system supports nested layouts, dynamic segments, catch-all routes, and route-level boundaries for errors and loading states.
The routing logic is primarily managed by the RouteManager component, which discovers routes from the file system, parses dynamic segments, and matches incoming URLs to the appropriate route handlers and layout chains.
Sources: ARCHITECTURE.md:120-128, README.md:144-150
Core Routing Components
The routing system relies on specific file names within the src/app directory to define the structure and behavior of the application.
File Conventions
| File Name | Purpose |
|---|---|
page.tsx | Defines the unique UI for a route and makes the path publicly accessible. |
layout.tsx | Defines shared UI for a segment and its children. Layouts nest automatically. |
loading.tsx | Defines an optional loading UI for a specific segment, wrapping children in a Suspense boundary. |
error.tsx | Defines an optional error UI boundary for a specific segment. |
not-found.tsx | Defines the UI shown when a route is not found. |
route.ts | Defines an API endpoint (cannot exist in the same directory as a page.tsx). |
Sources: README.md:180-205, skills/farmjs/SKILL.md:130-145, packages/farm/src/tests/route-manager.test.ts:325-345
Route Discovery and Matching
The RouteManager discovers routes by scanning the src/app directory for the conventions listed above. It distinguishes between static paths and dynamic segments using bracket syntax.
The matching process returns a result containing the target route module, the layout chain (from root to leaf), and any parsed dynamic parameters.
Sources: packages/farm/src/routing/route-manager.ts:1-20, ARCHITECTURE.md:129-134
Advanced Routing Patterns
Dynamic and Catch-all Segments
Dynamic segments allow routes to match variable URL parts. Catch-all routes can match multiple segments.
- Dynamic Segment:
src/app/users/[id]/page.tsxmaps to/users/:id. - Catch-all Segment:
src/app/blog/[...slug]/page.tsxmaps to/blog/*. - Optional Catch-all:
src/app/docs/[[...slug]]/page.tsxmaps to/docsand any sub-path.
Sources: skills/farmjs/SKILL.md:130-140, packages/farm/src/tests/route-manager.test.ts:115-135
Nested Layouts
Layouts are hierarchical. A layout defined in a parent directory wraps all pages and layouts in its child directories.
Route-Level Boundaries
Route-level boundaries are used to handle asynchronous operations and runtime errors gracefully.
loading.tsx: When a segment or its children suspend, this component renders automatically. You do not need to manually import it.error.tsx: This component receives theerrorobject and areset()function. It catches errors occurring in the page or any nested component within that segment.
Sources: examples/basic/README.md:85-105, README.md:216-240
Metadata and Special Routes
The routing system handles specialized metadata files that map to standard web conventions:
sitemap.tsmaps to/sitemap.xmlrobots.tsmaps to/robots.txtmanifest.tsmaps to/manifest.webmanifestllms.tsandllms-full.tsmap to/llms.txtand/llms-full.txt
Sources: skills/farmjs/SKILL.md:141-145, packages/farm/src/tests/route-manager.test.ts:510-540
Implementation Details
The RouteManager Class
The RouteManager class (located in packages/farm/src/routing/route-manager.ts) is the central authority for route resolution. It maintains internal maps of discovered routes, layouts, and boundaries.
Key methods include:
discoverRoutes(): Asynchronously scans the file system.matchRoute(pathname): Finds the most specific route and layout chain for a given URL.getMatchingLoading(pathname): Finds the nearest applicable loading boundary.getMatchingError(pathname): Finds the nearest applicable error boundary.
Sources: packages/farm/src/routing/route-manager.ts (class implementation), ARCHITECTURE.md:120-135
Production Build Integration
During the production build, Farm.js performs static analysis to discover all routes. The universal-build.ts logic generates a client manifest and an SSR (Server-Side Rendering) bundle that includes all route handlers. This ensures that route matching in production does not require file system access.
Sources: packages/farm/src/nitro/universal-build.ts:250-300, ARCHITECTURE.md:105-112