A Go framework for end-to-end type-safe APIs

Write Go.
TypeScript keeps up.

Write handlers as ordinary Go functions with struct inputs and outputs. ShiftAPI turns those types into an OpenAPI 3.1 spec at runtime, and the Vite or Next.js plugin turns the spec into a typed TypeScript client on every save. No codegen CLI, no hand-written spec.

$npm create shiftapi@latest
Get Started
Go
Structs
compile time
OAS
OpenAPI 3.1
runtime
TS
Types
build time
</>
Typed Client
your frontend

The Go struct is the TypeScript type.

Rename a field in Go and the frontend stops compiling at the call site, before anyone hits the endpoint.

main.go
type Input struct {
    Name string `json:"name"`
}

type Output struct {
    Hello string `json:"hello"`
}

func greet(r *http.Request, in Input) (*Output, error) {
    return &Output{Hello: in.Name}, nil
}

func main() {
    api := shiftapi.New()
    api.Handle("POST /greet", greet)
    shiftapi.ListenAndServe(":8080", api)
}
auto-generated
app.ts
import { client } from "@shiftapi/client";

// Types inferred from your Go structs
const { data } = await client.POST("/greet", {
    body: { name: "frank" },
});

console.log(data.hello);
//              ^? (property) hello: string

How it works

Go types in, TypeScript types out. Nothing in between is written by hand.

1

Define typed handlers

Write standard Go functions with struct input and output types. Tag fields with json, query, path, or header, and ShiftAPI binds each part of the request for you.

api.Handle("POST /greet", greet)
2

ShiftAPI generates the OpenAPI 3.1 spec at runtime

ShiftAPI reflects your Go types into a complete OpenAPI 3.1 schema and serves it at /openapi.json. The spec comes from the code, so it cannot drift from it.

GET /openapi.json → { "openapi": "3.1", ... }
3

TypeScript client via HMR

A Vite or Next.js plugin fetches the spec from your running Go server and generates the client. Save a Go file and the types update in the browser without a reload.

const { data } = await client.POST("/greet", ...) // ^? { hello: string }

The parts you would otherwise wire up yourself

Type-safe handlers

Generic Go functions capture request and response types at compile time. json, query, header, and form tags decide where each field is read from.

Validation included

ShiftAPI enforces struct tags like validate:"required,email" on every request and copies the same rules into your OpenAPI schema.

Vite & Next.js

Plugins that start your Go server, proxy API requests to it, and regenerate types on every save.

File uploads

Declare uploads with form tags. The TypeScript client gets the matching multipart/form-data types.

Interactive docs

A Scalar API reference at /docs and the raw spec at /openapi.json. Both come from the same generated schema.

Real-time

HandleSSE gives you typed server push through an sse helper. HandleWS does the same for bidirectional WebSockets.

Start with a working app

One command scaffolds a Go backend with a React, Svelte, or Next.js frontend, types wired end to end.

$npm create shiftapi@latest