Already have a Next.js app? Keep the frontend where it is and run Agentuity in an agentuity/ subdirectory. Next.js rewrites /api/* to the Agentuity dev server, and your frontend imports the backend router type directly for hc<ApiRouter>().
Project Structure
my-nextjs-app/
├── app/
│ ├── components/EchoDemo.tsx # Client component using hc<ApiRouter>()
│ └── page.tsx
├── agentuity/
│ ├── app.ts # createApp({ router, agents })
│ ├── src/agent/echo/agent.ts
│ └── src/api/index.ts # Exports ApiRouter
├── next.config.ts # Rewrites /api/* to Agentuity
└── package.jsonRewrite /api to Agentuity
Add a rewrite that proxies API traffic to agentuity dev. The SDK testing app runs Next.js on 3001 and Agentuity on 3501 to avoid conflicts:
import type { NextConfig } from 'next';
import { join } from 'path';
const nextConfig: NextConfig = {
// Only needed in monorepo/workspace setups where Next.js must trace
// dependencies above the app directory
outputFileTracingRoot: join(__dirname, '../../../..'),
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'http://localhost:3501/api/:path*',
},
];
},
};
export default nextConfig;This pattern does not use @agentuity/routes or src/generated/routes.ts. The frontend imports type ApiRouter directly from the backend source file, and hc() infers requests from that type.
Import the Router Type Directly
Export a router type from the backend:
import { Hono } from 'hono';
import type { Env } from '@agentuity/runtime';
import echoAgent from '@agents/echo/agent';
const router = new Hono<Env>()
.get('/health', (c) => {
return c.json({ status: 'ok', timestamp: new Date().toISOString() });
})
.post('/echo', echoAgent.validator(), async (c) => {
const input = c.req.valid('json');
return c.json(await echoAgent.run(input));
});
export type ApiRouter = typeof router;
export default router;Use that type in your Next.js client component:
'use client';
import { hc } from 'hono/client';
import type { ApiRouter } from '../../agentuity/src/api/index';
import { useState } from 'react';
const client = hc<ApiRouter>('/api');
export default function EchoDemo() {
const [message, setMessage] = useState('Hello from Next.js!');
const [response, setResponse] = useState<{ echo: string; timestamp: string } | null>(null);
const [error, setError] = useState<string | null>(null);
const sendEcho = async () => {
setError(null);
const res = await client.echo.$post({ json: { message } });
if (!res.ok) {
setError(`Echo request failed with ${res.status}`);
return;
}
setResponse(await res.json());
};
return (
<div>
<input
onChange={(e) => setMessage(e.target.value)}
value={message}
/>
<button onClick={sendEcho} type="button">Send Echo</button>
{error && <p>{error}</p>}
{response && <p>{response.echo}</p>}
</div>
);
}Use import type { ApiRouter } ... so the backend file is erased from the client bundle while hc() still gets full RPC inference.
Plain hc() calls do not require AgentuityProvider. Keep the client component focused on the typed Hono client unless you already depend on @agentuity/react.
Running Locally
Run from the project root (not from inside agentuity/):
bun install
bun run dev- Frontend:
http://localhost:3001 - Backend:
http://localhost:3501
bun run dev starts both runtimes. There is no separate client route-generation step in v2. The frontend imports the router type from source, and agentuity dev serves the backend.
Deployment
If you keep same-origin routing in production, keep hc<ApiRouter>('/api') and route /api/* to your Agentuity service at the host or CDN layer.
If the frontend and backend live on different origins, point hc() at the deployed backend instead:
const agentuityBaseUrl = process.env.NEXT_PUBLIC_AGENTUITY_BASE_URL;
if (!agentuityBaseUrl) {
throw new Error('NEXT_PUBLIC_AGENTUITY_BASE_URL is required');
}
const client = hc<ApiRouter>(new URL('/api', agentuityBaseUrl).toString());NEXT_PUBLIC_AGENTUITY_BASE_URL must be a full absolute URL, including the scheme, such as https://my-app.agentuity.run. new URL() throws if you pass a bare host or a relative path.
/api replaces any path suffix in NEXT_PUBLIC_AGENTUITY_BASE_URL. If your backend is mounted under a subpath, preserve it with a relative URL segment:
const baseUrl = new URL(agentuityBaseUrl);
if (!baseUrl.pathname.endsWith('/')) {
baseUrl.pathname += '/';
}
const client = hc<ApiRouter>(new URL('api', baseUrl).toString());Then enable CORS in App Configuration.
Next Steps
- RPC Client: More
hc()patterns, custom fetch, and error handling - Provider Setup: Add auth, analytics, or WebRTC hooks
- HTTP Routes: Define the backend API router you export to the frontend