End-to-end type safety for APIs and realtime. Define a contract once, implement it on the server, and use the same types from a client.
npm install @cablejs/contract @cablejs/core @cablejs/client zodWith Bun, use bun add with the same packages. Add an adapter for the runtime
that hosts your server, or @cablejs/react
for React. The installation guide lists
the smaller package sets for each runtime.
Define procedures and channel events in one contract.
import { c } from "@cablejs/contract";
import { z } from "zod";
export const api = c.contract({
profile: c.query({
input: z.object({ userId: z.string() }),
output: z.object({ name: z.string() }),
}),
chat: c.channel("chat.{roomId}", {
server: { message: z.object({ author: z.string(), text: z.string() }) },
client: { send: z.object({ text: z.string().min(1) }) },
}),
});Implement the procedure and channel on the server.
import { type ChannelImplementation, implement } from "@cablejs/core";
import { api } from "./api.js";
export const procedures = implement(api)
.context<{ readonly userId: string }>()
.procedures({
profile: ({ ctx, input }) => ({
name: input.userId === ctx.userId ? "Mina" : "Guest",
}),
});
export const chatImplementation = {
onClient: {
async send(context, { text }) {
await context.emit("message", { author: context.identity.userId, text });
},
},
procedures: {},
} satisfies ChannelImplementation<typeof api.chat, { userId: string }>;The client gets typed procedure calls and bidirectional channel events from the same contract.
import { createClient } from "@cablejs/client";
import { api } from "./api.js";
const client = createClient({ contract: api, url: "/_cable" });
const profile = await client.profile.query({ userId: "user-1" });
const room = client.chat({ roomId: "general" });
const unsubscribe = room.on("message", (message) => console.log(message.text));
await room.send({ text: `Hello from ${profile.name}` }, { ack: true });
unsubscribe();
room.dispose();- Quickstart follows a procedure from contract to client.
- Contracts explains procedures, inputs, outputs, and channels.
- Architecture explains clients, hosts, and runtime adapters.
- Authorization and grants cover request context and access control.
- Examples contains a runnable chat application.
For repository setup, checks, and contribution guidelines, read
CONTRIBUTING.md. The short version for a local checkout is:
bun install --frozen-lockfile
bun run setup:hooks
bun run checkcable is released under the MIT license.