Using Explicit Routing — Agentuity Documentation

Using Explicit Routing

Pass your own Hono router to createApp() when you need custom mount paths or an exported router type

When your API needs custom mount paths, multiple router mounts, or an exported type for hc<...>(), you can pass a Hono router directly to createApp({ router }). This gives you full control over route composition and where each router is mounted.

Basic Setup

Create a root router in src/api/index.ts, export its type, and wire it up from the project-root app.ts:

typescriptsrc/api/index.ts
import { Hono } from 'hono';
import type { Env } from '@agentuity/runtime';
 
const api = new Hono<Env>()
  .get('/health', (c) => c.json({ status: 'ok' }))
  .post('/users', async (c) => {
    const body = await c.req.json();
    return c.json({ created: body });
  });
 
export type ApiRouter = typeof api;
 
export default api;
typescriptapp.ts
import { createApp } from '@agentuity/runtime';
import api from './src/api/index'; 
import agents from './src/agent'; 
 
const app = await createApp({
  router: { path: '/api', router: api }, 
  agents,
});
 
export default app;

All Agentuity middleware is applied automatically at the mount path you provide.

Three Forms

The router property in createApp() accepts three forms, depending on how you want to organize your routes.

Plain Hono Instance

Pass a single router and it mounts at /api:

typescriptapp.ts
import { createApp } from '@agentuity/runtime';
import api from './src/api/index';
 
// Mounted at /api, routes are reachable at /api/health and /api/users
const app = await createApp({ router: api });
 
export default app;

Single Mount with Custom Path

Wrap the router in { path, router } to control the mount path:

typescriptapp.ts
import { createApp } from '@agentuity/runtime';
import api from './src/api/index';
 
// Mounted at /v1, routes are reachable at /v1/health and /v1/users
const app = await createApp({
  router: { path: '/v1', router: api }, 
});
 
export default app;

Multiple Mounts

Pass an array of { path, router } objects for multi-version or domain-split APIs:

typescriptapp.ts
import { createApp } from '@agentuity/runtime';
import v1Router from './src/api/v1';
import v2Router from './src/api/v2';
import internalRouter from './src/api/internal';
 
const app = await createApp({
  router: [ 
    { path: '/api/v1', router: v1Router }, 
    { path: '/api/v2', router: v2Router }, 
    { path: '/internal', router: internalRouter }, 
  ], 
});
 
export default app;

Each mount gets its own Agentuity middleware (CORS, OpenTelemetry, and route services on c.var.*) applied to {path}/*.

Composing Sub-Routers

For larger APIs, split routes across files and compose them with .route(). Keep the root router in chained form when you want to export a stable type for hc<...>().

typescriptsrc/api/users/route.ts
import { Hono } from 'hono';
import type { Env } from '@agentuity/runtime';
 
const usersRouter = new Hono<Env>()
  .get('/', async (c) => {
    return c.json({ users: [] });
  })
  .get('/:id', async (c) => {
    const id = c.req.param('id');
    return c.json({ id, name: 'Alice' });
  });
 
export default usersRouter;
typescriptsrc/api/index.ts
import { Hono } from 'hono';
import type { Env } from '@agentuity/runtime';
import postsRouter from './posts/route';
import usersRouter from './users/route';
 
const api = new Hono<Env>()
  .route('/users', usersRouter) 
  .route('/posts', postsRouter); 
 
export type ApiRouter = typeof api;
 
export default api;

This is standard Hono composition. Routes defined in users/route.ts are reachable at /api/users/ and /api/users/:id.

When to Use Explicit Routing

ScenarioApproach
Small API mounted only at /apiA single exported router is enough
Need custom mount paths (e.g., /v1, /internal)Explicit routing with { path, router }
API versioningMultiple mounts: [{ path: '/v1', router: v1 }, ...]
Exporting a router type for hc<ApiRouter>()Compose a root router and export typeof api
Monorepo with shared route modulesExplicit routing, compose imported routers

Migrating Existing Projects

If you're migrating a v1 project, use the dedicated migrator:

npx @agentuity/migrate

What the Migration Does

  1. Creates src/api/index.ts: A root router that imports and mounts your route modules with .route().
  2. Creates src/agent/index.ts: An agent barrel if your project does not already have one.
  3. Updates app.ts: Wires the generated barrels into createApp().
  4. Removes old v1 generated output: Run agentuity build afterward so the current v2 build regenerates any files it still needs.

Before and After

Before (v1 route modules):

src/api/
  users/
    route.ts
  posts/
    route.ts
  health/
    route.ts

After (explicit): You control the composition in src/api/index.ts.

typescriptsrc/api/index.ts
import { Hono } from 'hono';
import type { Env } from '@agentuity/runtime';
import healthRouter from './health/route';
import postsRouter from './posts/route';
import usersRouter from './users/route';
 
const api = new Hono<Env>()
  .route('/health', healthRouter)
  .route('/posts', postsRouter)
  .route('/users', usersRouter);
 
export type ApiRouter = typeof api;
 
export default api;
typescriptapp.ts
import { createApp } from '@agentuity/runtime';
import api from './src/api/index';
import agents from './src/agent';
 
const app = await createApp({
  router: { path: '/api', router: api },
  agents,
});
 
export default app;

Agentuity Context in Routes

new Hono<Env>() gives you access to Agentuity context variables in your route handlers:

import { Hono } from 'hono';
import type { Env } from '@agentuity/runtime';
 
const router = new Hono<Env>();
 
router.get('/example', async (c) => {
  // All Agentuity services are available on c.var
  c.var.logger.info('Handling request');
  const data = await c.var.kv.get('cache', 'key');
  return c.json({ data });
});
 
export default router;

Use c.json(), c.text(), and other Hono response methods in your handlers. Both new Hono<Env>() and createRouter() provide typed access to c.var.logger, c.var.kv, c.var.vector, c.var.thread, and other services.

Next Steps