# How to Handle Routing with Agent-Native: A Complete Guide to React Router Integration

> Learn how to handle routing with Agent-Native and React Router integration. Discover seamless routing across client, server, and agent runtime with this comprehensive guide.

- Repository: [Builder.io/agent-native](https://github.com/BuilderIO/agent-native)
- Tags: how-to-guide
- Published: 2026-06-21

---

**Agent-Native builds its UI on top of React Router and adds a thin abstraction layer that makes routing work seamlessly across the client, the server, and the agent runtime.**

Agent-Native templates unify standard React Router patterns with agent-aware navigation state, enabling both user interactions and background agent processes to control the application view. This architecture requires understanding three core components: static route definitions using `flatRoutes`, server-side request handling through Vite virtual modules, and the `NavigationState` bridge that keeps the UI and agent synchronized.

## Static Route Definition with flatRoutes

Agent-Native defines its route tree using React Router's file-system routing conventions. In [`templates/dispatch/app/routes.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/dispatch/app/routes.ts), you export a `RouteConfig` array generated by the `flatRoutes` helper.

```typescript
// templates/dispatch/app/routes.ts
import { type RouteConfig } from "@react-router/dev/routes";
import { flatRoutes } from "@react-router/fs-routes";

export const routes: RouteConfig[] = flatRoutes([
  { path: "/", element: <Overview /> },
  { path: "chat", element: <Chat /> },
  { path: "metrics", element: <Metrics /> },
]);

```

This configuration creates the baseline route tree that both the client and server use during rendering.

## Server-Side Rendering Entry Point

For SSR, Agent-Native uses a dedicated server entry point that imports the virtual React Router build. The [`templates/dispatch/ssr-entry.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/dispatch/ssr-entry.ts) file creates a request handler using React Router's `createRequestHandler` and loads routes from the virtual module `virtual:react-router/server-build`.

```typescript
// templates/dispatch/ssr-entry.ts
import { createRequestHandler } from "react-router";
import { defineServer } from "@builder.io/react";

export default defineServer({
  async handler() {
    return createRequestHandler({
      routes: () => import("virtual:react-router/server-build"),
    });
  },
});

```

This setup ensures server-rendered HTML matches the client-side route hierarchy exactly.

## Synchronizing Navigation State Between UI and Agent

The `useNavigationState` hook in [`templates/dispatch/app/hooks/use-navigation-state.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/dispatch/app/hooks/use-navigation-state.ts) forms the bridge between the browser URL and the agent runtime. It uses `useAgentRouteState` from [`packages/core/src/client/router.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/client/router.ts) to register callbacks that translate between browser locations and structured `NavigationState` objects.

```typescript
// templates/dispatch/app/hooks/use-navigation-state.ts
import { useLocation } from "react-router";
import { appBasePath, markAgentChatHomeHandoff, useAgentRouteState } from "@agent-native/core/client";

export function useNavigationState() {
  const location = useLocation();

  useAgentRouteState({
    getNavigationState: ({ pathname, search }) => {
      const cleanPath = routerPath(pathname);
      return buildDispatchNavigationState(cleanPath, search);
    },

    getCommandPath: (cmd) => {
      const path = cmd.path ?? resolvePath(cmd.view) ?? "/overview";
      return routerPath(path);
    },

    onNavigate: (cmd, path) => {
      if (routerPath(location.pathname) === "/chat" && pathnameFromPath(path) !== "/chat") {
        markAgentChatHomeHandoff("dispatch");
      }
    },
  });
}

```

The hook implements three critical functions:
- **getNavigationState**: Converts the current browser URL into a structured state object (view, extension, dream, etc.) that the agent can consume.
- **getCommandPath**: Resolves agent navigation commands into valid browser paths using `resolvePath`.
- **onNavigate**: Handles side effects when navigation occurs, such as marking handoff points between chat contexts.

## Handling Multi-App Workspace Paths

Agent-Native supports workspaces hosting multiple independent apps (e.g., `/dispatch`, `/calendar`). The `appBasePath()` and `appPath()` helpers in [`packages/core/src/workspace-files/tool.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/workspace-files/tool.ts) automatically manage workspace-level base paths, ensuring routes remain portable.

The `routerPath()` function normalizes URLs by stripping the `basename` repeatedly to prevent double-prefix bugs:

```typescript
function routerPath(path: string): string {
  const basePath = appBasePath(); // e.g., "/dispatch"
  if (!basePath) return path;
  let result = path;
  // Strip the basename up to 4 times to protect against double-prefix bugs
  for (let i = 0; i < 4; i++) {
    if (result === basePath) return "/";
    if (!result.startsWith(`${basePath}/`)) break;
    result = result.slice(basePath.length) || "/";
  }
  return result;
}

```

This normalization ensures the UI router and agent runtime agree on the current local pathname regardless of the app's mount point in the workspace.

## Triggering Navigation from Agent Actions

Agents navigate the UI by invoking the `navigate` action with a view name or path. The system uses `resolveView` and `resolvePath` (implemented in [`templates/dispatch/app/hooks/use-navigation-state.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/dispatch/app/hooks/use-navigation-state.ts) lines 146-226) to map between semantic view names and actual URL paths.

```typescript
import { defineAction } from "@agent-native/core";

export default defineAction({
  name: "openMetrics",
  description: "Navigate the UI to the Metrics page",
  run: async ({ agent }) => {
    await agent.navigate({ view: "metrics" });
  },
});

```

When the agent calls `navigate`, the `getCommandPath` callback resolves the view to a URL, `routerPath` normalizes it, and React Router performs the navigation.

## Summary

- **Agent-Native routing** extends React Router with agent-aware abstractions that work across client, server, and runtime environments.
- **Static routes** are defined in [`templates/dispatch/app/routes.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/dispatch/app/routes.ts) using `flatRoutes` and `RouteConfig` from React Router's dev tools.
- **Server rendering** uses `createRequestHandler` in [`templates/dispatch/ssr-entry.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/dispatch/ssr-entry.ts) to serve the virtual React Router build.
- **Navigation state** is synchronized through `useNavigationState`, which bridges browser URLs and agent commands via `useAgentRouteState` from [`packages/core/src/client/router.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/client/router.ts).
- **Path normalization** handles multi-app workspaces through `appBasePath()` and `routerPath()` to prevent routing errors when apps are mounted at sub-paths.

## Frequently Asked Questions

### How does Agent-Native handle base URL paths in multi-app workspaces?

Agent-Native uses the `appBasePath()` and `appPath()` helpers found in [`packages/core/src/workspace-files/tool.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/workspace-files/tool.ts) to automatically prepend or strip the workspace-level base path. The `routerPath()` function in [`templates/dispatch/app/hooks/use-navigation-state.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/dispatch/app/hooks/use-navigation-state.ts) strips the `basename` up to four times to guard against double-prefix bugs, ensuring each app can be developed in isolation and mounted at any sub-path without hardcoding.

### What is the difference between `routerPath` and `appBasePath`?

`appBasePath()` returns the workspace-level base URL (e.g., `/dispatch`) that prefixes all routes for the current app, while `routerPath()` is a normalization function that removes this base path from a URL to produce a clean local pathname. You use `appBasePath()` when constructing URLs to ensure they include the mount point, and `routerPath()` when parsing incoming URLs to determine the local route.

### How do agent commands trigger navigation in the UI?

When an agent calls `agent.navigate({ view: "metrics" })`, the `useAgentRouteState` hook (exposed from [`packages/core/src/client/router.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/client/router.ts)) invokes its `getCommandPath` callback. This callback uses `resolvePath` to map the view name to a URL, normalizes it with `routerPath()`, and returns the result to React Router's `navigate` function, triggering the actual browser navigation.

### Can I use standard React Router hooks alongside Agent-Native's routing?

Yes. Agent-Native is built directly on React Router, so hooks like `useLocation`, `useNavigate`, and `useParams` work normally. The `useNavigationState` hook internally uses `useLocation` to react to URL changes, meaning you can use standard hooks for UI-specific logic while reserving Agent-Native's `useAgentRouteState` for agent synchronization and workspace-aware path handling.