Routing Structure Generation and Conventions in OpenCut
OpenCut leverages TanStack Router's file-based routing system to automatically generate type-safe route trees from the src/routes directory, eliminating manual route configuration while ensuring compile-time path validation through the auto-generated routeTree.gen.ts file.
The OpenCut web application employs a modern, zero-configuration routing architecture powered by TanStack Router. This approach treats the filesystem as the source of truth for URL structure, automatically mapping TypeScript files in src/routes to application paths. Understanding these routing conventions is essential for extending the application's navigation structure while maintaining strict type safety.
Core Routing Files and Architecture
OpenCut's routing layer centers around three critical files that orchestrate navigation:
src/router.tsx– Instantiates the TanStack router with the generated route tree and global configuration options like scroll restoration and preloading.src/routeTree.gen.ts– Auto-generated TypeScript file containing the compile-time route map. Never edit this file manually; it regenerates automatically during the build process.src/routes/__root.tsx– The root route defining global HTML head elements, CSS imports, and shared layout providers.
These files work together to provide a type-safe navigation experience where route IDs, paths, and parameters are validated at compile time.
How the Route Tree Is Generated
The generation process follows a file-based discovery pattern. When you run npm run dev or bun run dev, TanStack Router scans the src/routes/**/*.tsx pattern and performs the following steps:
- File Discovery – Every file exporting a
Routeconstant created viacreateFileRoute(orcreateRootRoutefor the root) becomes a route entry. - Type Generation – The plugin writes
src/routeTree.gen.ts, containing concrete route objects (IndexRoute) and TypeScript interfaces (FileRoutesByFullPath,FileRoutesById). - Router Initialization –
src/router.tsximports the generatedrouteTreeand passes it tocreateTanStackRouter:
// src/router.tsx
import { createRouter as createTanStackRouter } from '@tanstack/react-router';
import { routeTree } from './routeTree.gen';
export function getRouter() {
return createTanStackRouter({
routeTree,
scrollRestoration: true,
defaultPreload: 'intent',
defaultPreloadStaleTime: 0,
});
}
The resulting router instance provides module augmentation that enables type-safe usage of useRouter() and <Link> components throughout the application.
File-Based Routing Conventions
OpenCut follows strict conventions to ensure predictable URL mapping:
- File Location – Place route files under
src/routes/; subdirectories create nested paths. - Index Routes – Use
index.tsxfor directory roots (maps to/). - Export Requirement – Must export a
Routeconstant usingcreateFileRoute. - Path Inference – URL path derived from file location unless overridden via options.
Creating a New Route
To add a Settings page at /settings, create src/routes/settings.tsx with the following structure:
// src/routes/settings.tsx
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/settings')({
component: SettingsPage,
});
function SettingsPage() {
return (
<div className="p-4">
<h1 className="text-2xl font-bold">Settings</h1>
{/* Settings UI implementation */}
</div>
);
}
After saving the file, the development server automatically regenerates routeTree.gen.ts, making the route immediately available without restarting the dev server.
The Root Route and Global Layout
The src/routes/__root.tsx file serves as the application shell, utilizing createRootRoute instead of createFileRoute. This route wraps all page content and provides:
- Global Head Management – Meta tags, viewport settings, and font preloading via the
headproperty. - CSS Injection – Global stylesheet imports (e.g.,
appCss). - Provider Wrapping –
TooltipProviderfor UI components. - Development Tools – TanStack Router devtools panel for debugging navigation.
// src/routes/__root.tsx
import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router';
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools';
import { TooltipProvider } from '../components/ui/tooltip';
import appCss from '../styles.css?url';
export const Route = createRootRoute({
head: () => ({
meta: [
{ charSet: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ title: 'OpenCut rewrite — beta.opencut.app' }
],
links: [
{ rel: 'icon', href: '/favicon.ico' },
{ rel: 'stylesheet', href: appCss },
],
}),
shellComponent: RootDocument,
});
function RootDocument({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head><HeadContent /></head>
<body>
<TooltipProvider>{children}</TooltipProvider>
<TanStackRouterDevtoolsPanel />
<Scripts />
</body>
</html>
);
}
All child routes render inside the RootDocument component, ensuring consistent styling and behavior across the application.
Type Safety and the Generated Route Tree
The routeTree.gen.ts file exports TypeScript interfaces that map file paths to route types:
export interface FileRoutesByFullPath {
'/': typeof IndexRoute;
'/settings': typeof SettingsRoute;
}
export interface FileRoutesById {
__root__: typeof rootRouteImport;
'/': typeof IndexRoute;
'/settings': typeof SettingsRoute;
}
These definitions enable IDE autocomplete for route IDs and compile-time validation of navigation calls. For example, router.navigate({ to: '/settings' }) will type-check against valid paths, preventing runtime 404 errors due to typos in route strings.
When you need to add loaders or search parameter validation, modify the route file (e.g., src/routes/settings.tsx) rather than the generated file. The build process will incorporate your changes into the type definitions automatically.
Summary
- File-based routing in OpenCut uses TanStack Router to map
src/routes/**/*.tsxfiles directly to URLs without manual configuration. - Auto-generation creates
routeTree.gen.tsduring the build process, providing compile-time type safety for all navigation operations. - Root route (
__root.tsx) defines global layout, meta tags, and development tools usingcreateRootRoute. - New routes require only a file in
src/routes/exporting aRouteconstant viacreateFileRoute, with paths inferred from the file location. - Never edit
routeTree.gen.tsmanually; modify source route files and let the generator update type definitions.
Frequently Asked Questions
How do I add a nested route like /projects/:id in OpenCut?
Create a directory structure under src/routes/ that mirrors the URL path. For /projects/:id, create src/routes/projects/$id.tsx (using the $ prefix for parameters). Export a Route using createFileRoute('/projects/$id') and access the parameter via the useParams hook. The file-based system automatically registers the dynamic segment.
What happens if I edit routeTree.gen.ts manually?
Manual edits to routeTree.gen.ts will be overwritten the next time the development server starts or the build runs. This file is purely generated output. To modify route behavior, edit the source route files in src/routes/ or adjust the router configuration in src/router.tsx.
Can I customize the route path to differ from the file path?
Yes. While TanStack Router infers the path from the file location by default, you can override it in the createFileRoute options. Pass a path property in the configuration object to specify a custom URL pattern that differs from the filesystem structure.
How does OpenCut handle 404 pages and error boundaries?
Define a notFoundComponent in your route configuration or utilize the root route's error handling. TanStack Router supports error boundaries through the errorComponent property on route definitions. For catch-all 404 routes, create a $.tsx file in src/routes/ to match unmatched paths.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →