Back-end Framework for Next.js App Router
One codebase → type-safe clients, OpenAPI, and AI tools
Documentation
Quick Start
Performance
Vovk.ts lets you build a structured back end on top of Next.js App Router Route Handlers—and generate a type-safe client, OpenAPI, and AI tools from the same code. Under the hood: you write Controllers, and Vovk emits schema artifacts for codegen—without maintaining a separate contract layer.
Requirements: Node.js 22+ and Next.js 15+
npx vovk-cli@latest initSee: https://vovk.dev/quick-install
- 🧩 Stay native to Next.js (routing, streaming, proxy.js/auth patterns, deployment targets)
- 🏗️ Structured API layer (Controller → Service → Repository) on top of Route Handlers
- 📝 No separate contract layer — schema is derived from your controller code, not maintained by hand
- 🤖 Derive AI tools from your API surface (controllers and emitted RPC modules can be exposed as AI tools with parameters +
execute) - ⚡ Back-end segmentation via segments: split your API into independently configured units that each compile into their own serverless function
- ✅ Typed request handling via
procedure(...)with{ params, query, body } - 🔗 Mix in third-party OpenAPI schemas as modules that share the same client/tooling pipeline (OpenAPI mixins)
Controller + decorator:
export default class UserController {
@get('{id}')
static async getUser(req: NextRequest, { id }: { id: string }) {
// ...
}
}With procedure you validate and type inputs in-place:
export default class UserController {
@get('{id}')
static getUser = procedure({
params: z.object({
id: z.string().uuid(),
})
}).handle(async (req, { id }) => {
// ...
});
}Procedures can use services that infer parameter types from the controller method signature:
import type { VovkParams } from 'vovk';
import type UserController from './UserController';
export default class UserService {
static async getUserById(id: VovkParams<typeof UserController.getUser>['id']) {
// ...
}
}import UserService from './UserService';
export default class UserController {
@get('{id}')
static getUser = procedure({ /*...*/ }).handle(async (req, { id }) => {
return UserService.getUserById(id);
});
}Codegen emits fetch-powered client:
import { UserRPC, PetstoreAPI } from 'vovk-client';
const user = await UserRPC.getUser({ params: { id: '123' } });
const pet = await PetstoreAPI.getPetById({ params: { petId: 1 } });Controllers (current context execution), RPC/API modules (HTTP calls) can be used to derive AI tools:
const { tools } = deriveTools({ modules: { UserRPC, TaskController, PetstoreAPI } });
console.log(tools); // [{ name, description, parameters, execute }, ...]Procedures can be executed locally for SSR/PPR:
await UserController.getUser.fn({ params: { id: '123' } });- Docs: https://vovk.dev
- Quick Start: https://vovk.dev/quick-install
- Manual install: https://vovk.dev/manual-install
- OpenAPI Mixins: https://vovk.dev/mixins
- Performance: https://vovk.dev/performance
- “Hello World” example app: https://github.com/finom/vovk-hello-world
License: MIT (see LICENSE).