Katman

Getting Started

Install Katman and build your first type-safe API in 5 minutes.

Install

npm install katman zod
pnpm add katman zod
bun add katman zod

You also need a validator. We use Zod here, but Valibot and ArkType also work.

What you will build

A small API with two endpoints:

  • users.list — returns a list of users (anyone can call it)
  • users.create — creates a user (requires authentication)

Project structure

rpc.ts
server.ts
package.json

Two files. That's all you need to get started.

Step by step

Create the Katman instance

This is where you tell Katman how to build the context for each request. The context is an object that every procedure can access — a good place to put things like a database connection.

src/rpc.ts
import {  } from "katman"

const  = ({
  : () => ({
    // This runs on every request.
    // Whatever you return here is available as `ctx` in procedures.
    : getDB(),
  }),
})

// Export the helpers you need
export const { , , , ,  } = 
export {  }

Define your procedures

A procedure is a single API endpoint. There are two kinds:

  • query — for reading data (like GET)
  • mutation — for writing data (like POST)
src/server.ts
import { , , , ,  } from "./rpc"
import {  } from "katman"
import {  } from "zod"

// A guard checks something before the procedure runs.
// If it returns an object, that object is added to the context.
const  = (() => {
  const  = .headers?.authorization
  if (!) throw new ("UNAUTHORIZED")
  return { : 1 }
})

// A query with input validation
const  = (
  .({ : .().(1).(100).() }),
  ({ ,  }) => {
    return .db.users.findMany({ : .limit ?? 10 })
  },
)

// A mutation that requires authentication
const  = ({
  : [],
  : .({
    : .().(1),
    : .().(),
  }),
  : ({ ,  }) => {
    return .db.users.create({ ..., : .userId })
  },
})

Create a router and start the server

The router groups your procedures. The structure becomes the API path: users.list becomes /users/list.

src/server.ts
// ... continuing from above

const  = router({
  : {
    : listUsers,
    : createUser,
  },
})

k.serve(, {
  : 3000,
  : true, // Serves API docs at /reference
})

Run it:

npx tsx src/server.ts

You should see:

Katman server running at http://127.0.0.1:3000
Scalar API Reference at http://127.0.0.1:3000/reference

Call it from the client

import {  } from "katman/client"
import {  } from "katman/client/ofetch"

// The link tells the client how to talk to the server
const  = ({ : "http://localhost:3000" })

// InferClient gives you the types from the router
const  = <any>()

// Now you have full autocomplete
const  = await .users.list({ : 5 })
const  = await .users.create({ : "Alice", : "[email protected]" })

In a real project, you would import the router type and use InferClient<typeof appRouter> instead of any. See the Client page for the full setup.

What's next?

Now that you have a working API, learn about the building blocks:

  • Core Concepts — how context, guards, and wraps work together
  • Procedures — the two forms: short and full config
  • Server — serve(), handler(), HTTP/2, Scalar
  • Client — ofetch link, binary mode, interceptors

On this page