Schema als Code.
Alles andere folgt.
Du schreibst Collections in TypeScript. Rebase hält Datenbank, API, Typen und — falls du es aktiviert hast — das Panel mit dieser einen Datei im Einklang. Führ pnpm dlx @rebasepro/cli init aus, dann rebase dev, und es läuft schon.
Die Schleife
Vier Befehle, und danach schreibst du einfach TypeScript
01
rebase initScaffold, or adopt what exists
Creates the three packages and wires them together. Already have a database? rebase schema introspect writes collections from your tables instead.
02
rebase db pushMove the schema
Diffs your collections against the database and applies the change. db generate + db migrate when you want the SQL in version control.
03
rebase generate-sdkRegenerate the types
Writes a typed client from your collections — or from a running backend with --from <url>, in a repo that has no schema of its own.
04
rebase devRun it, with no database to install
Backend and panel together with hot reload. No DATABASE_URL? A managed Postgres starts with them — nothing to install, no Docker, no compose file to maintain.
Das Projekt
Drei Ordner, eine Definition
config/collections/ ist der einzige Ort, an dem dein Datenmodell beschrieben wird. Das Backend liest es, um APIs auszuliefern und das Drizzle-Schema zu erzeugen; das Panel liest dieselben Dateien, um sich selbst zu rendern.
Lösch frontend/ und du hast ein Headless-Backend. Nichts unter backend/ importiert React, und das Typsystem setzt das durch — ein admin-Key in einem Projekt, das das nie aktiviert hat, ist ein Compile-Fehler.
my-app/
├── config/collections/ # the source of truth
│ ├── index.ts
│ └── orders.ts # properties · relations · securityRules · admin
│
├── backend/ # Hono server
│ ├── src/index.ts # initializeRebaseBackend(…)
│ ├── src/schema.generated.ts # Drizzle, generated
│ └── functions/ # your own routes, auto-mounted
│
├── frontend/ # the admin panel — delete it and nothing breaks
│ └── src/App.tsx
│
└── .env # DATABASE_URL, JWT_SECRET, …Dein Code
Generiert heißt nicht geschlossen
Jede generierte Oberfläche hat eine Naht, die du öffnen kannst: Callbacks um Schreibvorgänge, eigene Routen auf dem Server, eigenes React im Panel und rohes SQL, wenn die Abstraktion im Weg steht.
export const orders = {
slug: "orders",
callbacks: {
onPreSave: async ({ values, context }) => {
values.total = recalculate(values.items);
return values;
},
onSaveSuccess: async ({ entity, context }) => {
await context.rebase.sql(
"INSERT INTO ledger (order_id) VALUES ($1)",
{ params: [entity.id] },
);
},
},
};Geschäftslogik läuft auf dem Server, auf jedem Schreibpfad — auch bei Schreibvorgängen aus dem Admin-Panel.
// backend/functions/checkout.ts
import { Hono } from "hono";
const app = new Hono();
app.post("/", async (c) => {
const { user, rebase } = c.get("rebase");
// same auth context, same RLS as every other request
return c.json({ ok: true });
});
export default app;
// → POST /api/functions/checkoutLeg eine Datei in functions/ ab, und sie ist gemountet, authentifiziert und RLS-gebunden — ohne Registrierungsschritt.
import type { PostgresCollectionConfig } from "@rebasepro/types"; export const postsCollection: PostgresCollectionConfig = { name: "Posts", slug: "posts", table: "posts", properties: { id: { name: "ID", type: "string", validation: { required: true } }, title: { name: "Title", type: "string" }, status: { name: "Status", type: "string", validation: { required: true } } } };
Rebase lets non-technical editors build database schemas visually. Any change updates the database instantly and generates type-safe AST code modifications.
drizzle-kit push:postgresResources
Deklariere, was du brauchst. Im Code, einmal.
Datenbanken, Buckets und Topics sind Konstruktoren, kein YAML. Jedes benennt seine eigene Engine — Postgres, MongoDB, Firestore, SQLite; lokale Platte, S3, GCS, Azure — und eine Engine, von der wir nie gehört haben, schreibt sich custom: und wird akzeptiert, damit sie an der Aufrufstelle scheitert statt wie ein Tippfehler auszusehen.
rebase resources erzeugt den Graphen, den ein Host liest, bevor er irgendetwas baut, und --check lässt die CI scheitern, wenn der committete Graph und dein Code auseinandergehen. Es gibt keinen zweiten Ort, an dem man einen Bucket deklariert — genau das ist der Punkt: zwei Heimaten für eine Tatsache heißt, eine davon verliert still.
// config/resources.ts
import { database, bucket, topic } from "@rebasepro/types";
export const analytics = database("analytics", { engine: "mongodb" });
export const media = bucket("media", { engine: "s3", transport: "direct" });
export const signups = topic<{ userId: string }>("signups");
signups.subscription("send-welcome", async (event) => {
// durable, at-least-once, retried on its own schedule
});
await signups.publish({ userId });In einer Transaktion zu publizieren, die zurückgerollt wird, war nie ein Publish. Jeder Subscriber wiederholt nach eigenem Zeitplan, und einer, der aufgibt, ist eine Zeile, die du dir ansehen kannst.
Architecture
Wo jedes Teil tatsächlich läuft
Dein Browser, dein Server, deine Datenbank. Nichts läuft über uns — im Request-Pfad gibt es kein uns.
serverRow-Level SecurityRolesLifecycle Hooks@rebasepro/clientBrowser · Node · Serverless · Edgedatabase.types.tsrebase.data.*rebase.auth.*rebase.realtime.*rebase.storage.*rebase.functions.*rebase.cron.*rebase.email.*rebase.admin.*@rebasepro/cliOrchestrates schema, migrations, SDK codegen, dev server, and builds.
@rebasepro/uiSchema-as-Code · Git-Backed · Hot Reload · Self-Hostable · TypeScript End-to-End · 21 Packages
Ship it
Es deployt wie die Node-App, die es ist
Das Backend baut zu einem Bundle und läuft hinter dem, was du ohnehin nutzt. Das Admin-Panel ist eine statische SPA — liefere sie aus demselben Prozess oder von einem CDN aus.
Ein Prozess ist die Voreinstellung und bleibt es. Wenn du herauswächst, startet dasselbe Bundle als API, Functions-Tier und Worker — REBASE_ROLE pro Prozess, und daraus folgt, welche Routen gemountet werden, welche Timer feuern und wem das Schema gehört. Genau ein Prozess migriert; die übrigen prüfen sich gegen die Datenbank und sagen Bescheid, wenn sie nicht übereinstimmen.
Self-hosted gehört jedes Deployment dir: deine Datenbank, deine Maschine, deine Logs. Rebase Cloud, unser Managed Hosting, betreibt dasselbe Bundle für dich — heute in der Private Beta, geöffnet in Wellen.
Self-hosting guide- DockerA Dockerfile ships with every scaffolded backend.
- RailwayPush the repo, set DATABASE_URL, done.
- Fly.ioOne process, one region or several.
- Hetzner · bare metalIt is a Node server. Run it the way you run Node.
- AWS · GCP · Azure · ScalewayA deployment guide per provider in the docs.
- Your existing Hono appMount the backend as a sub-app instead of deploying it separately.
Deine Agenten auch
Bring deinem Coding-Agenten Rebase bei
rebase skills install schreibt gepackte Anweisungen in Claude Code, Cursor, Windsurf oder Gemini, sodass ein Agent in deinem Repo schon weiß, wie Collections, Policies und Panel zusammenhängen. Der MCP-Server gibt ihm Werkzeuge — Schema-Introspektion, Migrationen, Queries, Storage, Cron — unter einem gescopten Key, auf den Row-Level Security weiterhin greift.
Starte die Schleife.
Ein Befehl scaffoldet das Projekt, erzeugt das SDK aus deinem Schema und startet das Panel daneben.