Skip to content

Quickstart

Go from zero to a running TypoKit API in under 5 minutes. By the end of this guide you’ll have a type-safe API server with auto-generated validation, routing, and OpenAPI docs.

  • Node.js 24+Download
  • A package manager — pnpm (recommended), npm, or yarn
Terminal window
npm install -g pnpm
  1. Scaffold your app

    Run the TypoKit initializer to create a new project:

    Terminal window
    pnpm dlx @typokit/cli scaffold init my-app --server native --db raw

    You should see output like:

    ✔ Created my-app/
    ✔ Initialized package.json
    ✔ Installed dependencies
    ✔ Generated project structure
    Your TypoKit project is ready!
    cd my-app && typokit dev
  2. Enter your project and install dependencies

    Terminal window
    cd my-app
    pnpm install
  3. Explore the project structure

    Your scaffolded project looks like this:

    my-app/
    ├── src/
    │ ├── app.ts # App factory — registers routes and middleware
    │ ├── types.ts # Your schema type definitions
    │ ├── routes/ # Route modules (you'll add these next)
    │ ├── middleware/ # Global middleware
    │ └── services/ # Business logic layer
    ├── package.json
    ├── tsconfig.json
    └── .typokit/ # Auto-generated (validators, routes, schemas)

    See the Project Structure page for a full breakdown.

  4. Define a type

    Open src/types.ts. This is where you define your domain types — the single source of truth for your entire stack:

    src/types.ts
    /** @table */
    export interface Todo {
    /** @id @generated uuid */
    id: string;
    /** @minLength 1 @maxLength 200 */
    title: string;
    completed: boolean;
    /** @generated now */
    createdAt: Date;
    }
    export type CreateTodoInput = Omit<Todo, "id" | "createdAt">;

    TypoKit reads these plain TypeScript types and generates validators, database schemas, and OpenAPI definitions automatically. No decorators, no Zod — just types.

    Learn more in Schema-First Types.

  5. Create a route

    Define a route contract and handler for your Todo type:

    src/routes/todos/contracts.ts
    import type { RouteContract } from "@typokit/types";
    import type { Todo, CreateTodoInput } from "../../types.ts";
    export interface TodoRoutes {
    "GET /todos": RouteContract<void, void, void, Todo[]>;
    "POST /todos": RouteContract<void, void, CreateTodoInput, Todo>;
    "GET /todos/:id": RouteContract<{ id: string }, void, void, Todo>;
    }
    src/routes/todos/handlers.ts
    import type { HandlerInput } from "@typokit/core";
    import type { TodoRoutes } from "./contracts.ts";
    import type { Todo } from "../../types.ts";
    const todos: Todo[] = [];
    type RouteHandlerFn<Route extends keyof TodoRoutes> = (
    input: HandlerInput<TodoRoutes[Route]>
    ) => Promise<TodoRoutes[Route]["response"]>;
    const handlers: { [Route in keyof TodoRoutes]: RouteHandlerFn<Route> } = {
    "GET /todos": async () => {
    return todos;
    },
    "POST /todos": async ({ body }) => {
    const todo = {
    id: crypto.randomUUID(),
    title: body.title,
    completed: body.completed,
    createdAt: new Date(),
    };
    todos.push(todo);
    return todo;
    },
    "GET /todos/:id": async ({ params, ctx }) => {
    const todo = todos.find((t) => t.id === params.id);
    return todo ?? ctx.fail(404, "TODO_NOT_FOUND", `Todo ${params.id} not found`);
    },
    };
    export default handlers;

    Learn more in Routing and Handlers.

  6. Register the route in your app

    src/app.ts
    import { createApp } from "@typokit/core";
    import { nativeServer } from "@typokit/server-native";
    import todoHandlers from "./routes/todos/handlers.ts";
    export const app = createApp({
    server: nativeServer(),
    routes: [
    {
    prefix: "/todos",
    handlers: todoHandlers,
    },
    ],
    });
    app.listen({ port: 3000 }).then(() => {
    console.log("🚀 Server running at http://localhost:3000");
    });
  7. Start the dev server

    Terminal window
    pnpm typokit dev

    You should see:

    ✔ Schema introspection complete (2 types found)
    ✔ Validators generated
    ✔ Routes compiled
    ✔ OpenAPI spec generated
    🚀 Server running at http://localhost:3000
    👀 Watching for changes...
  8. Test your API

    Open a new terminal and try it out:

    Terminal window
    # Create a todo
    curl -X POST http://localhost:3000/todos \
    -H "Content-Type: application/json" \
    -d '{"title": "Learn TypoKit", "completed": false}'
    {
    "id": "a1b2c3d4-...",
    "title": "Learn TypoKit",
    "completed": false,
    "createdAt": "2026-03-02T12:00:00.000Z"
    }
    Terminal window
    # List all todos
    curl http://localhost:3000/todos
    [
    {
    "id": "a1b2c3d4-...",
    "title": "Learn TypoKit",
    "completed": false,
    "createdAt": "2026-03-02T12:00:00.000Z"
    }
    ]

With just a few TypeScript types and a handful of files, TypoKit:

  • Validated your request body against the CreateTodoInput type
  • Routed requests to the correct handler with full type safety
  • Generated an OpenAPI spec at /openapi.json
  • Watched your files for changes and rebuilt incrementally

Now that you have a running app, dive deeper: