Silgi

Getting Started

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

Install

bash npm install silgi zod
bash pnpm add silgi zod
bash bun add silgi 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 Silgi instance

This is where you tell Silgi 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 'silgi'

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. All procedures default to POST. Use .$route({ method: 'GET' }) for read-only endpoints.

src/server.ts
import { , ,  } from './rpc'
import {  } from 'silgi'
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 procedure with input validation
const  = s.$input(.({ : .().(1).(100).() })).$resolve(({ ,  }) => {
  return .db.users.findMany({ : .limit ?? 10 })
})

// A procedure that requires authentication
const  = 
  .$use()
  .$input(
    .({
      : .().(1),
      : .().(),
    }),
  )
  .$resolve(({ ,  }) => {
    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,
  },
})

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

Run it:

npx tsx src/server.ts

You should see:

Silgi 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 'silgi/client'
import {  } from 'silgi/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 builder pattern for defining endpoints
  • Server — serve(), handler(), HTTP/2, Scalar
  • Client — ofetch link, binary mode, interceptors

On this page