Devtools

API Types

Publish your API's types as a package your clients install instead of the server.

mion api-types builds a package that holds only your API's types. A client installs it instead of your whole server, and builds against the same ids.

Publishing a Types-Only Package

Run it from your server project. Its name is your server's plus -types, and its version is your server's. Change them with --name and --version.

mion api-types --tsconfig tsconfig.json --out api-types
cd api-types && npm publish
In the packageWhat it is for
.d.ts filesThe exported API and every type it reaches. Private and raw middlewares, server-only code, unused global declarations, and their imports are left out.
_outside/The types your API uses from other libraries, one file per library.
mion-pure-fns/Pure functions and overrides your clients can use, so they compute the same ids.
.mion/vendor/Pure functions from other libraries that your clients need.
.mion/api/manifest.jsonLets mion api-check compare a client build with this server build.
mion-api.jsonThe marker a client checks.
package.jsonNo JavaScript entry. Peer dependencies on the mion packages and on your tsconfig libraries.
A client refuses a package with types and no JavaScript entry unless mion api-types built it (rpc-client-types-not-built-by-mion). Build the client with the same mion version as the package (rpc-client-types-other-mion-version).

Dependencies the Client Installs

A client installs the types package, the mion packages, and the libraries your tsconfig types and lib load, such as @types/node. Nothing else: a type your API takes from any other library ships inside the package. The package entry loads the same tsconfig libraries, so the client gets your server's ids whatever its own tsconfig lists.

_outside/geo-lib.d.ts
export type Address = {city: string; street: string};
export declare enum Role { Admin = 'admin', User = 'user' }
A library type used with one of your type parameters (Page<T> in your own generic type) cannot be copied. It stays an import, its library stays a peer dependency, and mion api-types prints a warning naming it.

Classes and Enums From Other Libraries

A class or enum from another library is copied as a type only, with its name and members, so its ids do not change. A method's type parameters are not copied: map<T>(fn: (v: number) => T): T[] shows as map(fn: (v: number) => unknown): unknown[]. To get class instances back from the API, install that library in your client and register its class as usual:

import {registerClassSerializer} from '@mionjs/run-types/runtime';
import {Money} from 'money-lib';

registerClassSerializer(Money, {deserialize: (data) => new Money(data.amount)});

Installing a Copied Library in the Client

If your client installs a library the package copied, its types and the copies are separate declarations. Plain objects mix fine, but a class with private fields, a unique symbol or an enum from one does not fit the other: TypeScript reports "is not assignable". Ids and runtime are not affected.

Building a Client From Published API Types

Build your API package with mion compile and declaration: true, and its .d.ts carries the server's build version. A client calling initClient<typeof api>() on that type checks its ids against the version at build time, and fails with rpc-client-server-version-mismatch if they differ (another tsconfig or library version).

export declare const api: PublicApi<{...}> & ApiBuildVersion<"k3Jd92xQaP1z">;
Types written by plain tsc carry no version, so the client builds with the warning rpc-client-no-server-version and a mismatch only shows at runtime. They also lose the type of every private class field, so a route type holding such a class fails the client build with marker-untyped-private-member.

Types-Only Package Compared With OpenAPI

A types-only package does for TypeScript clients what an OpenAPI spec does for other stacks. A client that fetches its routes from the server (client: {routes: 'fetch'}) needs no package.

Types-only packageOpenAPI spec
Who can read itTypeScript clients built with mionAny language or tool
ValidationThe client compiles the server's validators from the same typesEach tool builds its own from the schema, so they can differ
Drift checkThe build fails on a mismatch (rpc-client-server-version-mismatch); the version is also checked at runtimeNone built in
VersionA hash of the route ids, set by the buildWritten by hand
Copyright © 2026