Skip to content

Architecture Overview

Rebase is a full-stack platform with four layers:

┌─────────────────────────────────────────────────────────────────┐
│ Frontend Layer │
│ React Admin UI • Custom Views • Plugins • Your App │
│ @rebasepro/core • @rebasepro/ui • @rebasepro/studio │
└───────────────────────────┬─────────────────────────────────────┘
│ HTTP + WebSocket
┌─────────────────────────────────────────────────────────────────┐
│ Backend Layer │
│ Hono HTTP Server • REST API • Auth • Storage • WS │
│ @rebasepro/backend │
└───────────────────────────┬─────────────────────────────────────┘
│ Drizzle ORM
┌─────────────────────────────────────────────────────────────────┐
│ Database Layer │
│ PostgreSQL • Tables • RLS Policies • LISTEN/NOTIFY │
└─────────────────────────────────────────────────────────────────┘

The backend supports multiple database drivers simultaneously. Each driver handles CRUD operations, search, and real-time notifications for its connected database.

// Single driver (most common)
driver: {
connection: db,
schema: { tables, enums, relations }
}
// Multiple drivers
driver: {
"(default)": postgresConfig,
"analytics": analyticsDbConfig
}

Collections specify which driver they use via the driver property. Collections without a driver use "(default)".

The BackendCollectionRegistry is the runtime index of all collections, their database tables, enums, and Drizzle relations. It’s populated at startup from your collection definitions.

Real-time sync uses PostgreSQL’s native LISTEN/NOTIFY mechanism:

  1. A data mutation happens (insert, update, delete)
  2. The backend emits a NOTIFY on a Postgres channel
  3. The RealtimeService receives the notification
  4. It broadcasts the change to all connected WebSocket clients
  5. React components re-render with the new data

For multi-instance deployments (e.g., Cloud Run with multiple replicas), provide a connectionString in your driver config. This creates a dedicated Postgres connection for cross-instance broadcasting.

Like drivers, storage backends are registered in a registry. You can have multiple storage providers (local, S3) and route different file fields to different backends using storageId.

PackageRoleUsed By
@rebasepro/typesTypeScript interfaces for collections, properties, entities, pluginsEverything
@rebasepro/backendBackend server initialization, REST API, auth, storage, WebSocketBackend
@rebasepro/clientClient SDK — HTTP transport, WebSocket, authFrontend
@rebasepro/coreReact framework — Scaffold, controllers, forms, routes, hooksFrontend
@rebasepro/uiStandalone UI component library (Tailwind v4 + Radix)Frontend
@rebasepro/authLogin views, auth controller hooks, user managementFrontend
@rebasepro/studioCollection editor, SQL console, JS console, RLS editor, storage browserFrontend
@rebasepro/cliCLI for schema generation, DB migrations, SDK generationDev tooling
@rebasepro/formexLightweight React form state managementFrontend
@rebasepro/data_enhancementAI-powered field autocompletion pluginFrontend
@rebasepro/data_import_exportCSV/JSON/Excel import and exportFrontend
@rebasepro/schema_inferenceAuto-detect schema from existing database dataBackend/CLI
  1. User opens a collection in the admin UI
  2. Client SDK sends GET /api/data/:slug + opens a WebSocket subscription
  3. Backend queries PostgreSQL via Drizzle ORM
  4. Data transformer deserializes database rows into entity format
  5. Response sent to frontend, components render
  6. WebSocket keeps the view synced in real-time
  1. User edits an entity in the form
  2. beforeSave callbacks run (validation, transformation)
  3. Client SDK sends PUT /api/data/:slug/:id
  4. Backend serializes values, runs Drizzle UPDATE
  5. afterSave callbacks run (side effects)
  6. NOTIFY broadcast triggers WebSocket update to all clients
  7. If history is enabled, a snapshot is recorded