Sapporta

Sapporta

Build Database Applications in TypeScript

  • Editable data grids
  • Generated REST APIs
  • Forms and reports
  • Row-scoped auth
  • Agent-ready OpenAPI
  • Integrated stack
packages/api/schema/books.ts
export const booksTable = sqliteTable("books", {
  id: integer("id").primaryKey({ autoIncrement: true }),
  title: text("title").notNull(),
  author: text("author").notNull(),
});

export const books = sapportaTable({
  drizzle: booksTable,
  meta: {
    label: "Books",
    rowScope: "systemGlobal",
    rowLabelColumns: ["title"],
    search: { columns: ["author", "title"] },
    children: [
      {
        table: "quotes",
        foreignKey: "book_id",
        label: "Quotes",
        columns: ["quote_text"],
        defaultSort: "-created_at",
      },
    ],
    columns: {
      title: { width: 64 },
      author: { width: 36 },
    },
  },
});

Sapporta helps you build applications that operate mostly on relational data - like personal databases, operational tools, and business software.

  • Grids Editable table UI with search, sort, filters, nesting, and keyboard flow.
  • Reports Summary rows, detail rows, and drill-down links.
  • REST APIs for every table CRUD, lookup, count, export, and typed custom endpoints.
  • Forms Validated data entry with reliable keyboard navigation.
  • Security Workspace and role scoped reads and writes.
  • Deployment Project wiring from npx sapporta init to production.

The rich user experience of collaborative databases

Just like creating a new spreadsheet, in Sapporta, once you define a table, you immediately get a live editable grid. The grid brings a similar set of features and UX as that of AirTable, NocoDB and similar collaborative databases. It is filterable, sortable, and searchable. They also support nested master-detail relationships, and full keyboard support that work across levels.

The APIs used by the grid are bounded by row-level security and CASL authorization, and so it can be shipped directly to end users without additional hardening.

Not an opaque framework

There is no inversion of control - Sapporta projects are regular Hono APIs + React single page applications that your codebase owns completely. There are no opaque abstractions that obscures control-flow or hide the underlying implementation.

Agentic development

Sapporta projects are structured for coding agents. The generated codebase follows explicit conventions for project structure. These conventions cover data modeling, API behavior, UI flows, access rules, and migrations. Sapporta also ships sapporta-skills for table creation, reports, row access, custom endpoints, and frontend workflows. The legible-code skill applies domain types, module boundaries, and the functional core, imperative shell design to agent-authored TypeScript.

Type-safe APIs and auth

Every table exposes auto-generated REST endpoints (list, create, update etc.), that adhere to row-level security and CASL authorization policies.

APIs don't require manual JSON wiring for request/response parsing. Both the auto-generated APIs, as well as any domain APIs you write, are all defined using ts-rest. The definitions go into packages/shared, and are immediately available in the frontend as typed functions.

Agentic use, out of the box

Applications that you build with Sapporta can be operated fully agentically by default. Agents can insert new rows, or update existing rows, map freeform data into database entries, execute multi-step workflows, run reports, and answer data questions, all through the same APIs used by the application UI.

For example, if you built an Expense Tracking system with Sapporta, then its users can scribble reimbursement details - rough vendor names, relative dates, all in a freeform structure - into an LLM agent, and have it be recorded accurately in the database. This requires no additional code (but the user needs to have the Sapporta skill installed).

This works because Sapporta publishes the application's API surface at /api/openapi.json. It has detailed route descriptions, usage examples, and documented request parameters for every available endpoint. This includes all the automatically generated table APIs as well as any domain specific APIs written by you.

It is also secure by default - since all endpoints are secured by row-security and CASL, the agents only have access to the exact data that the user themselves have.

Get Started GitHub