Skip to Content
Manual Install

Manual Install

Create a Next.js project (App Router + TypeScript)

npx create-next-app my-app --ts --app --src-dir
cd my-app

Install vovk and vovk-cli

  • vovk is the runtime library.
  • openapi3-ts gives the OpenAPI types that the types of vovk import. It’s a peer dependency of vovk, and not every package manager installs one.
  • vovk-cli is the Vovk.ts command-line tool, a development dependency.
npm i vovk openapi3-ts
npm i -D vovk-cli

More info:

Create the config file

Create vovk.config.mjs in the project root:

vovk.config.mjs
// @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-ajv

Set validateOnClient in the config file to turn on client-side validation:

vovk.config.mjs
// @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.

Install concurrently, and cross-env, which sets PORT on Windows too:

npm i -D concurrently cross-env

Update 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.

src/modules/hello/hello-controller.ts
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 [[…mySlug]].

In the code below, HelloRPC is the name of the generated RPC module, and HelloController is the controller from the previous step.

src/app/api/[[...vovk]]/route.ts
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 dev

Open 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.

src/app/page.tsx
'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:

Last updated on