Skip to main content

TypeScript backend

TypeScript backend support is in alpha

The core of Reboot — durable state, transactions, workflows, tasks, and the standard library — works in both Python and TypeScript, but some features are currently Python-only, including MCP UIs, UI methods, the built-in OAuth sign-in flow — and therefore User auto-construction — and durable agents. If you don't have a strong preference for TypeScript, prefer starting with Python.

  1. Set up your app folder
    mkdir reboot-chat-room && cd reboot-chat-room
  2. Install Reboot
    npm init -y && npm pkg set type="module" && npm install @reboot-dev/reboot zod@^4.0.0 && npx tsc --init --sourceMap --declaration --moduleResolution node --target es2020 --rootDir . --outDir dist
  3. Make sure Docker is running
    docker ps
  4. Define your API using Zod
    mkdir -p ./api/chat_room/v1 && touch ./api/chat_room/v1/chat_room.ts
  5. Define your durable state data types and operations
    // ./api/chat_room/v1/chat_room.ts
    import { reader, writer } from "@reboot-dev/reboot-api";
    import { z } from "zod/v4";

    export const ChatRoom = {
    state: {
    messages: z
    .array(z.string())
    .default(() => [])
    .meta({ tag: 1 }),
    },
    methods: {
    messages: reader({
    request: {},
    response: {
    messages: z.array(z.string()).meta({ tag: 1 }),
    },
    }),
    send: writer({
    request: {
    message: z.string().meta({ tag: 1 }),
    },
    response: {},
    }),
    },
    };

    export const api = {
    ChatRoom,
    };
  6. Create .ts implementation file
    mkdir -p ./backend/src && touch ./backend/src/chat_room_servicer.ts
  7. Implement ChatRoomServicer
    // ./backend/src/chat_room_servicer.ts
    import { ReaderContext, WriterContext } from "@reboot-dev/reboot";
    import { ChatRoom } from "../../api/chat_room/v1/chat_room_rbt.js";

    export const chatRoomServicer = ChatRoom.servicer({
    messages: async (
    context: ReaderContext,
    state: ChatRoom.State,
    request: ChatRoom.MessagesRequest
    ): Promise<ChatRoom.MessagesResponse> => {
    return { messages: state.messages };
    },

    send: async (
    context: WriterContext,
    state: ChatRoom.State,
    request: ChatRoom.SendRequest
    ): Promise<[ChatRoom.State, ChatRoom.SendResponse]> => {
    state.messages.push(request.message);
    return [state, {}];
    },
    });
  8. Create a main entrypoint
    touch ./backend/src/main.ts
  9. Implement main.ts
    // ./backend/src/main.ts
    import { Application, InitializeContext } from "@reboot-dev/reboot";
    import { ChatRoom } from "../../api/chat_room/v1/chat_room_rbt.js";
    import { chatRoomServicer } from "./chat_room_servicer.js";

    const initialize = async (context: InitializeContext) => {
    const chatRoom = ChatRoom.ref("reboot-chat-room");

    await chatRoom.send(context, { message: "Hello, World!" });
    };

    new Application({
    servicers: [chatRoomServicer],
    initialize,
    }).run();
  10. Create an .rbtrc file
    touch .rbtrc
  11. Add necessary flags to your .rbtrc file
    # .rbtrc
    generate api/
    generate --nodejs=api/

    dev run --application-name=chat-room
    dev run --watch=backend/src/**/*.ts
    dev run --nodejs
    dev run --application=backend/src/main.ts
  12. Run your app
    npx rbt dev run
  13. Query your app
    curl -XPOST http://localhost:9991/chat_room.v1.ChatRoomMethods/Messages \
    -H "x-reboot-state-ref:chat_room.v1.ChatRoom:reboot-chat-room"

Next steps

Well done! You made it!

This example is somewhat contrived: it creates just one instance of your ChatRoom data type, but in practice you are free to make as many of these as you like!

Check out these links to continue your exploration:

Hopefully, your wheels are starting to spin thinking of all of the possibilities!