Introduction
A type-safe way to write GraphQL in plain TypeScript — no codegen, no build step, works with any client or server.
Typograph is a tiny TypeScript library for writing GraphQL on the client and the server. You define your schema once in plain TypeScript, and everything else — the queries you write, the variables you pass, the responses you get back, the resolvers on your server — is fully typed from that single source of truth.
There's no codegen step, no .graphql files to maintain, and nothing
to compile in the background. You write TypeScript, and you get
GraphQL.
What it actually does
At its core, typograph is a translator. You describe what you want using a normal JavaScript object, and typograph turns that into a standard GraphQL string. That's it.
client.query({
getPost: {
id: true,
title: true,
author: { name: true },
},
});Becomes:
query GetPost {
getPost {
id
title
author {
name
}
}
}Because the output is just a plain GraphQL string and a plain
variables object, you can hand it to any GraphQL client — urql,
Apollo, graphql-request, React Query, plain fetch, anything. And
because the input is just TypeScript, your editor knows exactly what
fields you can select, what variables you need to pass, and what shape
your data will come back in.
Why people use it
Framework agnostic
Works with any GraphQL client and any backend. Use it with React, Vue, Svelte, Node, Bun, or just plain fetch.
Zero codegen
No build step, no watcher, no generated files to commit. Your types are always in sync because they live in the same place as your schema.
One source of truth
Define the schema once and use it everywhere — client selections, server resolvers, and the SDL itself all derive from the same TypeScript object.
Tiny runtime
The library is mostly type magic. The runtime is a thin wrapper that turns your JavaScript objects into GraphQL strings.
Real GraphQL out the other end
Typograph emits standard SDL and standard query strings. Your server still speaks GraphQL — typograph just makes it nicer to write.
First-party React integrations
Drop-in typed useQuery / useMutation / useSubscription hooks for urql, Apollo Client, and React Query. Or skip them entirely and use the core client with anything else.
A quick taste
Here's the smallest possible example — define a type, declare a query, and run it through the client. The selection set, the variables, and the result are all typed with no extra effort.
import { createTypeDefBuilder, t, createClient } from "@overstacked/typograph";
const builder = createTypeDefBuilder();
const post = builder.type({
id: t.string(),
title: t.string(),
});
const typeDefs = builder.combineTypeDefs([
builder.typeDef({
Post: post,
Query: {
getPost: builder.query({
input: t.type({ id: t.string().notNull() }),
output: t.type<Post>("Post"),
}),
},
}),
]);
type Post = typeof post;
const client = createClient(typeDefs);
const res = client.query(
{ getPost: { id: true, title: true } },
{ variables: { id: "p1" } },
);
type Result = typeof res.returnType;
// ^? { getPost: { id: string; title: string } }If you change the schema, the call site updates automatically. If you remove a field from a type, every place that selected it lights up red in your editor. There's no codegen step you need to remember to run.