Skip to content

kwannoel/surf

Repository files navigation

Surf

A reactive backend framework for building real-time applications. Declare your schema, define queries that compile to materialized views, write mutations, and get live-updating data in React — all with end-to-end type safety.

Built on RisingWave, a streaming SQL database.

Quick Start

npm install surf

Define Your Schema

// surf/schema.ts
import { defineTable, defineSchema, v } from "surf/server"

export default defineSchema({
  todos: defineTable({
    text: v.string(),
    done: v.boolean(),
  }),
})

Define Queries

// surf/queries/allTodos.ts
import { query, v } from "surf/server"

export default query({
  args: {},
  query: (q) => q.from("todos").orderBy("createdAt", "desc"),
})

Define Mutations

// surf/mutations/addTodo.ts
import { mutation, v } from "surf/server"

export default mutation({
  args: { text: v.string() },
  handler: async (ctx, args) => {
    await ctx.db.insert("todos", { text: args.text, done: false })
  },
})

Use in React

import { useQuery, useMutation } from "surf/react"

function TodoList() {
  const todos = useQuery("allTodos", {})
  const addTodo = useMutation("addTodo")

  return (
    <div>
      <button onClick={() => addTodo({ text: "New todo" })}>Add</button>
      {todos?.map((t) => <div key={t.id}>{t.text}</div>)}
    </div>
  )
}

How It Works

  1. Schema definitions map to RisingWave tables
  2. Queries compile to materialized views that RisingWave maintains incrementally
  3. Mutations write to tables, which automatically update the materialized views
  4. Subscriptions stream changes from materialized views over WebSocket to React hooks

When a mutation inserts a row, RisingWave incrementally updates the materialized view, and every subscribed client receives the new data — no polling, no manual cache invalidation.

Tech Stack

Layer Technology
Database RisingWave (streaming SQL, PG-compatible)
Server Node.js, TypeScript, ws, pg
Client TypeScript, WebSocket
React Hooks (useQuery, useMutation), Context provider
Testing Vitest

Package Exports

Export Contents
surf/server defineTable, defineSchema, query, mutation, v, SurfServer
surf/client SurfClient
surf/react SurfProvider, useQuery, useMutation

Development

npm run build         # Compile TypeScript to dist/
npm run dev           # Watch mode
npm test              # Run unit tests
npm run test:watch    # Watch mode for tests

Integration tests require RisingWave running on :4566:

npx vitest run tests/integration/

Demo: Prediction Market

The demo/ directory contains a prediction market app that showcases real-time updates. The benchmark/ directory includes a trade generator and dashboard for comparing MV-based subscriptions vs re-query polling under load.

npm run demo:mv         # Start with MV subscriptions (fast)
npm run demo:requery    # Start with re-query polling (slow)
npm run benchmark       # Generate trade load

See ARCHITECTURE.md for a detailed breakdown of the system design.

License

MIT

About

Reactive backend framework built on RisingWave

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors