Manual Install
Create a Next.js project (App Router + TypeScript)
npx create-next-app my-app --ts --app --src-dircd my-appInstall vovk and vovk-cli
vovkis the runtime library.openapi3-tsgives the OpenAPI types that the types ofvovkimport. It’s a peer dependency ofvovk, and not every package manager installs one.vovk-cliis the Vovk.ts command-line tool, a development dependency.
npm i vovk openapi3-tsnpm i -D vovk-cliMore info:
Create the config file
Create vovk.config.mjs in the project root:
// @ts-check
/** @type {import('vovk').VovkConfig} */
const vovkConfig = {};
export default vovkConfig;More info:
Install a validation library and enable client-side validation
To validate with Zod on the server and with Ajv on the client, install:
npm i zod vovk-ajvSet validateOnClient in the config file to turn on client-side validation:
// @ts-check
/** @type {import('vovk').VovkConfig} */
const vovkConfig = {
outputConfig: {
imports: {
validateOnClient: 'vovk-ajv',
},
},
};
export default vovkConfig;More info:
Update the dev script and add a prebuild script
You can run Vovk.ts and the Next.js server together in two ways. The explicit way runs both with the concurrently package, and you set PORT. The implicit way lets the Vovk.ts CLI start Next.js, and vovk-cli picks the port.
The prebuild script runs vovk generate before next build, so the client library exists when Next.js builds. Yarn 2+ doesn’t run pre scripts: there, use "build": "vovk generate && next build" instead.
Explicit
Install concurrently, and cross-env, which sets PORT on Windows too:
npm i -D concurrently cross-envUpdate the “dev” script in package.json:
"scripts": {
"build": "next build",
"dev": "cross-env PORT=3000 concurrently \"vovk dev\" \"next dev\" --kill-others",
"prebuild": "vovk generate"
}More info:
Enable decorators
In tsconfig.json, set "experimentalDecorators" to true. vovk init sets it too.
{
"compilerOptions": {
"experimentalDecorators": true
// ...
}
}A webpack build needs the flag: without it, next build --webpack fails, and webpack is the default build in Next.js 15. Turbopack, the default in Next.js 16, compiles Vovk.ts decorators with or without the flag, and TypeScript 5.0+ type-checks them either way. See Decorators Overview for the decorators Vovk.ts provides.
Create a controller
Create hello-controller.ts in /src/modules/hello/ with a HelloController class.
import { get, prefix } from 'vovk';
@prefix('greetings') // prefix is optional
export default class HelloController {
@get('greeting')
static getHello() {
return { greeting: 'Hello, World!' };
}
}More info:
Create a root segment
Create the root segment /src/app/api/[[…vovk]]/route.ts. [[…vovk]] is an “Optional Catch-all Segment” ; the slug can be any valid name, such as
In the code below, HelloRPC is the name of the generated RPC module, and HelloController is the controller from the previous step.
import { initSegment } from 'vovk';
import HelloController from '../../../modules/hello/hello-controller';
const controllers = { HelloRPC: HelloController };
// the client infers its types from this
export type Controllers = typeof controllers;
// export Next.js route handlers
export const { GET, POST, PATCH, PUT, HEAD, OPTIONS, DELETE } = initSegment({ controllers });More info:
Run the dev server
Run npm run dev to start Vovk.ts and Next.js together.
npm run devOpen http://localhost:3000/api/greetings/greeting to see the result.
Create a React component
Once the client is generated to src/client, import it as @/client, or with a relative path if your project has no @/* alias.
'use client';
import { useState } from 'react';
import { HelloRPC } from '@/client';
import type { VovkReturnType } from 'vovk';
export default function MyComponent() {
const [serverResponse, setServerResponse] = useState<VovkReturnType<typeof HelloRPC.getHello>>();
return (
<>
<button
onClick={async () => {
const response = await HelloRPC.getHello();
setServerResponse(response);
}}
>
Get Greeting from Server
</button>
<div>{serverResponse?.greeting}</div>
</>
);
}Open http://localhost:3000 to see the result.
In VS Code, you may need to restart the TS server after you add a new controller class. Other changes, such as new methods or new validation, are picked up without a restart.
More info: