Get started
Pick the stack you work in. Each guide builds the same bookshop: books with an author and a stock count, a cost price only staff can see, and two commands, buy and restock. Every server listens on port 4000 and speaks the same protocol, so the React app works just as well against the Kotlin server as against the TypeScript one.
TypeScriptServer and client on Node.jsReactHooks that follow the cacheKotlinServer and client, Android-readyJavaPlain Java 21 serverSpring BootAnnotated beans and Spring Security
The code on these pages comes from the example projects, whose tests run on every change to the repository. Not ready to install anything? The playground runs the bookshop server in your browser.
The schema you will serve
Every guide starts from this file. It is the contract: the server is checked against it, and clients learn from it what they can ask for.
rayfold
entity Author {
id: ID
name: String
}
entity Book @cache(maxAge: 60s, scope: public) {
id: ID
title: String
stock: Int
author: Author
"""What the shop paid. Only staff can see it."""
costPrice: Decimal? @allow(read: viewer.role == "staff")
}
error OutOfStock { bookId: ID, available: Int }
event StockChanged { bookId: ID, stock: Int }
query book(id: ID): Book?
query books(page: PageArgs = { first: 20 }): Page<Book>
"""Take copies off the shelf. Fails if there are not enough."""
command buy(bookId: ID, qty: Int = 1 @range(min: 1, max: 10)): Book
throws OutOfStock
emits StockChanged
@allow(write: viewer != null)
command restock(bookId: ID, qty: Int @range(min: 1, max: 1000)): Book
emits StockChanged
@allow(write: viewer.role == "staff")- Fields are required unless they end in
?. @allowsays who may readcostPriceor runrestock, and the server enforces it on every request.buydeclares that it can fail withOutOfStock, so clients can handle that case by name.Page<Book>givesbooksa cursor, a total and ahasMoreflag without any extra code.