T
TanStack2w ago
continuing-cyan

Safe way to use the createRouter singleton without circular imports?

Hey all! Quick question, in a React + Vite app, is the router singleton (from createRouter) actually meant to be imported and used anywhere in the app? I’ve noticed that it can easily cause circular import issues — the singleton imports the route tree and the route tree is importing the page definitions (component). If a page then imports the singleton, it loops back and causes problems. Has anyone figured out the recommended way to use the router instance without running into these circular imports? Or if it is even recommended to export the router and use it as a singleton? Thanks in advance!
// Example showing circular import problem with TanStack Router in a single file context

// ❌ This util directly uses the router singleton
const someUtil = () => tanstackRouter.location

// Page component
export const AuditTrail: React.FC = () => {
// Using a util that references the router
const utilResult = someUtil();

return <div>Current location: {JSON.stringify(utilResult)}</div>;
};

// Route definition
export const Route = createFileRoute('/_authenticated/audit')({
component: AuditTrail,
});

// Router singleton
// ❌ Depends on the routeTree, which includes AuditTrail → creates circular import
export const tanstackRouter = createRouter({ routeTree });

// ---- Notes ----
// Import chain causing circular dependency:
// AuditTrail (page) -> someUtil -> tanstackRouter -> routeTree -> AuditTrail
// This is why importing the singleton inside pages or utils used by pages causes issues.
// Example showing circular import problem with TanStack Router in a single file context

// ❌ This util directly uses the router singleton
const someUtil = () => tanstackRouter.location

// Page component
export const AuditTrail: React.FC = () => {
// Using a util that references the router
const utilResult = someUtil();

return <div>Current location: {JSON.stringify(utilResult)}</div>;
};

// Route definition
export const Route = createFileRoute('/_authenticated/audit')({
component: AuditTrail,
});

// Router singleton
// ❌ Depends on the routeTree, which includes AuditTrail → creates circular import
export const tanstackRouter = createRouter({ routeTree });

// ---- Notes ----
// Import chain causing circular dependency:
// AuditTrail (page) -> someUtil -> tanstackRouter -> routeTree -> AuditTrail
// This is why importing the singleton inside pages or utils used by pages causes issues.
4 Replies
continuing-cyan
continuing-cyanOP2w ago
Bump
optimistic-gold
optimistic-gold6d ago
I dont think you should use the exported router anywhere else than to provide it for the RouterProvider. Any aspect of the router is available via hooks or any other API - useLocation, useRouter, useSearch etc. At least that is the case for file based routing.
metropolitan-bronze
metropolitan-bronze5d ago
Actually, this is not true at all, the router instance is done like that, so in case you do needed you can export it and use it, at least it was mentioned in a question before. The problem with circular deps is a bit annoying, nothing you can do, other than structure your application better, i found that the hard way actually
optimistic-gold
optimistic-gold4d ago
sure you can do it but then it seems like a very edge case. In my app there is not a single API I could not fetch with either any hooks or if its very specific with getRouteApiFunction https://tanstack.com/router/latest/docs/framework/react/api/router/getRouteApiFunction
getRouteApi function | TanStack Router React Docs
The getRouteApi function provides type-safe version of common hooks like useParams, useSearch, useRouteContext, useNavigate, useLoaderData, and useLoaderDeps that are pre-bound to a specific route ID...

Did you find this page helpful?