Typebase is een tool die backend-ontwikkeling versimpelt door de backend te transformeren tot een typebase/ map binnen de eigen codebase. Hierdoor kunnen ontwikkelaars hun databaseschema's, server-acties en authenticatie definiëren in TypeScript, wat resulteert in een volledig getypeerde server die door de frontend als lokale functies kan worden aangeroepen.
De werking en implementatie:
- Workflow: Via een CLI (
npx typebase-io-cli) wordt de structuur aangemaakt, waarna de ontwikkelaar TypeScript-code schrijft voor schema's, acties, authenticatie en omgevingsvariabelen.
- Deployment: De server kan worden gedeployed naar Vercel, Cloudflare Workers of Deno Deploy, waarbij gebruik wordt gemaakt van Postgres op Neon.
- Technologie: Typebase is gebouwd op Drizzle ORM, RPC en better-auth.
Belangrijkste voordelen:
- Type Safety: Het biedt end-to-end type safety, waardoor fouten vroegtijdig door de compiler worden gesignaleerd.
- Expliciete Autorisatie: In tegenstelling tot Row Level Security (RLS), die vaak impliciet en lastig te controleren is, hanteert Typebase expliciete autorisatie in de code.
- Geen Vendor Lock-in: In vergelijking met diensten als Convex en Supabase biedt Typebase meer openheid en flexibiliteit in infrastructuurkeuze.
Het systeem is compatibel met populaire frameworks zoals Next.js, SvelteKit, Nuxt en Expo.
Typebase: je backend is een map met TypeScript
Voorbeeld van implementatie
Server-side: typebase/actions/queries/todos.ts
import { action } from '../../_generated/server';
import { z } from 'zod';
export const getMany = action
.output(z.array(z.object({
id: z.number(),
value: z.string(),
})))
.handler(async ({ db }) => {
return db.query.todos.findMany();
});
Client-side: src/app/page.tsx
import { client } from '@/lib/typebase/client';
export default async function Page() {
const todos = await client.queries.todos.getMany();
// ^? { id: number; value: string }[]
return todos.map((t) => (
<li key={t.id}>{t.value}</li>
));
}
Typebase biedt eersteklas gidsen voor:
- Next.js
- SvelteKit
- Nuxt
- Expo
Voor elk framework zijn er idiomatische clients beschikbaar: Server Components, SvelteKit load-functies, Nuxt-plugins en Expo SecureStore.
Gebouwd op: Drizzle ORM, RPC en better-auth.
---
Hoe het werkt
Van nul naar een geïmplementeerde backend in twee commando's. Alles gebeurt binnen je eigen codebase; de CLI regelt de codegeneratie, schema-pushes en implementatie.
1. Scaffold
Eén commando maakt een typebase/ map aan in je bestaande app, inclusief een databaseschema, voorbeeldacties en optionele authenticatie of realtime publishing. Geen aparte repository, geen dashboard. $ npx typebase-io-cli init
2. TypeScript schrijven
Definieer tabellen in db/schema.ts, exporteer acties vanuit actions/, en voeg auth.ts, env.ts en publisher.ts toe voor authenticatie, omgevingsvariabelen en realtime functionaliteit. Elke export wordt end-to-end typechecked.
3. Implementeren
Je map wordt als server verzonden naar Vercel, Cloudflare Workers of Deno Deploy, met Postgres op Neon. Je kunt ook de servercode genereren en deze overal hosten. Typebase beheert zelf geen servers. $ npx typebase-io-cli deploy
---
Gedetailleerd overzicht van de mappenstructuur
typebase/
actions/
mutations/
todos.ts
queries/
todos.ts
db/
relations.ts
schema.ts
auth.ts
env.ts
publisher.ts
Bestanden en configuratie
typebase/db/schema.ts (Jouw definities) Gebruik Drizzle onder de motorkap.
import { p } from 'typebase-io/db';
export const todos = p.pgTable('todos', {
id: p.integer().primaryKey().generatedAlwaysAsIdentity(),
value: p.varchar({ length: 255 }).notNull(),
completed: p.boolean().notNull(),
createdAt: p.timestamp().notNull().defaultNow(),
});
typebase/db/relations.ts (Jouw definities) Registreert tabellen voor db.query.todos.*
import { q } from 'typebase-io/db';
import * as schema from './schema.ts';
export const relations = q.defineRelations(schema, (r) => ({
todos: {},
}));
typebase/actions/queries/todos.ts (Jouw definities) Wordt client.queries.todos.getMany()
import { z } from 'zod';
import { action } from '../../_generated/server.ts';
export const getMany = action
.output(z.array(z.object({
id: z.number(),
value: z.string(),
completed: z.boolean(),
})))
.handler(async ({ db }) => {
return db.query.todos.findMany();
});
typebase/actions/mutations/todos.ts (Jouw definities) Wordt client.mutations.todos.create()
import { z } from 'zod';
import { action } from '../../_generated/server.ts';
import { todos } from '../../db/schema.ts';
export const create = action
.input(z.object({ value: z.string().min(1) }))
.handler(async ({ db, input }) => {
await db.insert(todos).values({
value: input.value,
completed: false,
});
});
typebase/auth.ts (Jouw definities) Sessies, OAuth, e-mail/wachtwoord in één bestand.
import { defineAuth } from 'typebase-io/server';
export const auth = defineAuth({
trustedOrigins: ['http://localhost:3000'],
emailAndPassword: { enabled: true },
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
},
},
});
typebase/env.ts (Jouw definities) Als er iets mist, start de server niet op.
import { defineEnv } from 'typebase-io/server';
import { z } from 'zod';
export const env = defineEnv({
RESEND_API_KEY: z.string().min(1),
STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
});
// Gebruik in elke actie: ({ env }) => env.RESEND_API_KEY
typebase/publisher.ts (Jouw definities) Events die je acties publiceren en streamen.
import { definePublisher } from 'typebase-io/server';
import { z } from 'zod';
export const publisher = definePublisher({
provider: 'db',
events: {
'todo.created': z.object({ id: z.number() }),
},
});
// Gebruik vervolgens: .stream(async function* ({ publisher }) { ... })
---
Het probleem met RLS
Row Level Security (RLS) is impliciet en geschreven in een SQL-dialect dat je editor niet typecheckt. Eén UPDATE-policy geeft schrijftoegang tot elke kolom, inclusief de kolommen die je morgen toevoegt. Een te permissive clause die een AI-agent om 02:00 uur 's nachts heeft toegevoegd, glipt door de review, omdat geen enkele compiler dit zal signaleren.
Met Typebase is autorisatie expliciet. Je actie verklaart welke kolommen hij accepteert en je auth-check wordt in code uitgevoerd voordat er iets de database bereikt. Als je een kolom toevoegt, vertelt de compiler je wie er in mag schrijven. Dezelfde code die je agent schrijft, is de code die je compiler controleert.
---
Vergelijking: De DX van Convex, de openheid van Supabase
Typebase is ontstaan vanuit de behoefte aan backend-functies die in je eigen code leven, ondersteund door een database die je daadwerkelijk bezit.
| Kenmerk | Typebase | Supabase | Convex |
| Backend logica | TypeScript functies | SQL + RLS policies | TypeScript functies |
| Database | Standaard Postgres | Postgres | Proprietary |
| Type safety | End-to-end, altijd synchroon | Gegenereerd, kan afwijken | End-to-end |
| Realtime | Streaming acties over SSE | Realtime subscriptions | Reactive queries |
| Auth | better-auth, in één bestand | Ingebouwd, dashboard config | Third-party providers |
| Infrastructuur | Jouw cloud: Vercel, Cloudflare, Deno | Supabase-hosted | Convex-hosted |
| Vendor lock-in | Geen, altijd uitstapmogelijkheid | Medium | High |
Let op: Storage is nog niet beschikbaar; dit staat als volgende op de roadmap.
---
Getuigenissen
Let op: Geen van deze mensen bestaat. We hebben het twee keer gecontroleerd. Legal vindt het prima.
"Ik heb afgelopen kwartaal 40.000 regels REST-plumbing verwijderd. Mijn tech lead begon te huilen. Ik denk dat het gelukstranen waren. Ik heb opgehouden met vragen."
— Mariel Vonnegut, Principal Eng, AI unicorn
"Voor Typebase had ik drie acroniemen in mijn pipeline: REST, gRPC en WHY. Nu heb ik er één: fn(). Ik ben nog nooit gelukkiger geweest en mijn Oura-ring is het ermee eens."
— Dave Dave, Senior Fullstack, waarschijnlijk
"Ik heb vier verschillende therapeuten verteld over Typebase. Twee stopten me als cliënt. De andere twee bouwen nu een app ermee."
— Clementine Ryu, Engineer, tussen therapeuten door
"Mijn co-founder vroeg waar de auth staat. Ik zei: 'in een bestand genaamd auth.ts'. Hij heeft sindsdien niet meer tegen me gesproken. Ik neem aan dat hij onder de indruk is."
— Tomás Lindberg, Indie hacker, mogelijk single
"We hebben 14 microservices vervangen door één map. Het DevOps-team gaf een feestje voor me. Het feestje was een vergadering. De vergadering ging over ontslagen."
— Anoniem, om voor de hand liggende redenen
"10/10 zou mijn backend opnieuw een map maken."
— Hannah Pollard, Senior Folder Engineer, zelfbenoemd
---
Geef je AI-agent een backend die hij kan lezen
Het kost ongeveer negentig seconden. Het grootste deel daarvan is npm install.
$ npm i typebase-io && npm i -D typebase-io-cli
Typebase: je backend is een map met TypeScript
Voorbeeld van implementatie
Server-side: typebase/actions/queries/todos.ts
import { action } from '../../_generated/server';
import { z } from 'zod';
export const getMany = action
.output(z.array(z.object({
id: z.number(),
value: z.string(),
})))
.handler(async ({ db }) => {
return db.query.todos.findMany();
});
Client-side: src/app/page.tsx
import { client } from '@/lib/typebase/client';
export default async function Page() {
const todos = await client.queries.todos.getMany();
// ^? { id: number; value: string }[]
return todos.map((t) => (
<li key={t.id}>{t.value}</li>
));
}
Typebase biedt eersteklas gidsen voor:
- Next.js
- SvelteKit
- Nuxt
- Expo
Voor elk framework zijn er idiomatische clients beschikbaar: Server Components, SvelteKit load-functies, Nuxt-plugins en Expo SecureStore.
Gebouwd op: Drizzle ORM, RPC en better-auth.
---
Hoe het werkt
Van nul naar een geïmplementeerde backend in twee commando's. Alles gebeurt binnen je eigen codebase; de CLI regelt de codegeneratie, schema-pushes en implementatie.
1. Scaffold
Eén commando maakt een typebase/ map aan in je bestaande app, inclusief een databaseschema, voorbeeldacties en optionele authenticatie of realtime publishing. Geen aparte repository, geen dashboard. $ npx typebase-io-cli init
2. TypeScript schrijven
Definieer tabellen in db/schema.ts, exporteer acties vanuit actions/, en voeg auth.ts, env.ts en publisher.ts toe voor authenticatie, omgevingsvariabelen en realtime functionaliteit. Elke export wordt end-to-end typechecked.
3. Implementeren
Je map wordt als server verzonden naar Vercel, Cloudflare Workers of Deno Deploy, met Postgres op Neon. Je kunt ook de servercode genereren en deze overal hosten. Typebase beheert zelf geen servers. $ npx typebase-io-cli deploy
---
Gedetailleerd overzicht van de mappenstructuur
typebase/
actions/
mutations/
todos.ts
queries/
todos.ts
db/
relations.ts
schema.ts
auth.ts
env.ts
publisher.ts
Bestanden en configuratie
typebase/db/schema.ts (Jouw definities) Gebruik Drizzle onder de motorkap.
import { p } from 'typebase-io/db';
export const todos = p.pgTable('todos', {
id: p.integer().primaryKey().generatedAlwaysAsIdentity(),
value: p.varchar({ length: 255 }).notNull(),
completed: p.boolean().notNull(),
createdAt: p.timestamp().notNull().defaultNow(),
});
typebase/db/relations.ts (Jouw definities) Registreert tabellen voor db.query.todos.*
import { q } from 'typebase-io/db';
import * as schema from './schema.ts';
export const relations = q.defineRelations(schema, (r) => ({
todos: {},
}));
typebase/actions/queries/todos.ts (Jouw definities) Wordt client.queries.todos.getMany()
import { z } from 'zod';
import { action } from '../../_generated/server.ts';
export const getMany = action
.output(z.array(z.object({
id: z.number(),
value: z.string(),
completed: z.boolean(),
})))
.handler(async ({ db }) => {
return db.query.todos.findMany();
});
typebase/actions/mutations/todos.ts (Jouw definities) Wordt client.mutations.todos.create()
import { z } from 'zod';
import { action } from '../../_generated/server.ts';
import { todos } from '../../db/schema.ts';
export const create = action
.input(z.object({ value: z.string().min(1) }))
.handler(async ({ db, input }) => {
await db.insert(todos).values({
value: input.value,
completed: false,
});
});
typebase/auth.ts (Jouw definities) Sessies, OAuth, e-mail/wachtwoord in één bestand.
import { defineAuth } from 'typebase-io/server';
export const auth = defineAuth({
trustedOrigins: ['http://localhost:3000'],
emailAndPassword: { enabled: true },
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
},
},
});
typebase/env.ts (Jouw definities) Als er iets mist, start de server niet op.
import { defineEnv } from 'typebase-io/server';
import { z } from 'zod';
export const env = defineEnv({
RESEND_API_KEY: z.string().min(1),
STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
});
// Gebruik in elke actie: ({ env }) => env.RESEND_API_KEY
typebase/publisher.ts (Jouw definities) Events die je acties publiceren en streamen.
import { definePublisher } from 'typebase-io/server';
import { z } from 'zod';
export const publisher = definePublisher({
provider: 'db',
events: {
'todo.created': z.object({ id: z.number() }),
},
});
// Gebruik vervolgens: .stream(async function* ({ publisher }) { ... })
---
Het probleem met RLS
Row Level Security (RLS) is impliciet en geschreven in een SQL-dialect dat je editor niet typecheckt. Eén UPDATE-policy geeft schrijftoegang tot elke kolom, inclusief de kolommen die je morgen toevoegt. Een te permissive clause die een AI-agent om 02:00 uur 's nachts heeft toegevoegd, glipt door de review, omdat geen enkele compiler dit zal signaleren.
Met Typebase is autorisatie expliciet. Je actie verklaart welke kolommen hij accepteert en je auth-check wordt in code uitgevoerd voordat er iets de database bereikt. Als je een kolom toevoegt, vertelt de compiler je wie er in mag schrijven. Dezelfde code die je agent schrijft, is de code die je compiler controleert.
---
Vergelijking: De DX van Convex, de openheid van Supabase
Typebase is ontstaan vanuit de behoefte aan backend-functies die in je eigen code leven, ondersteund door een database die je daadwerkelijk bezit.
| Kenmerk | Typebase | Supabase | Convex |
| Backend logica | TypeScript functies | SQL + RLS policies | TypeScript functies |
| Database | Standaard Postgres | Postgres | Proprietary |
| Type safety | End-to-end, altijd synchroon | Gegenereerd, kan afwijken | End-to-end |
| Realtime | Streaming acties over SSE | Realtime subscriptions | Reactive queries |
| Auth | better-auth, in één bestand | Ingebouwd, dashboard config | Third-party providers |
| Infrastructuur | Jouw cloud: Vercel, Cloudflare, Deno | Supabase-hosted | Convex-hosted |
| Vendor lock-in | Geen, altijd uitstapmogelijkheid | Medium | High |
Let op: Storage is nog niet beschikbaar; dit staat als volgende op de roadmap.
---
Getuigenissen
Let op: Geen van deze mensen bestaat. We hebben het twee keer gecontroleerd. Legal vindt het prima.
"Ik heb afgelopen kwartaal 40.000 regels REST-plumbing verwijderd. Mijn tech lead begon te huilen. Ik denk dat het gelukstranen waren. Ik heb opgehouden met vragen."
— Mariel Vonnegut, Principal Eng, AI unicorn
"Voor Typebase had ik drie acroniemen in mijn pipeline: REST, gRPC en WHY. Nu heb ik er één: fn(). Ik ben nog nooit gelukkiger geweest en mijn Oura-ring is het ermee eens."
— Dave Dave, Senior Fullstack, waarschijnlijk
"Ik heb vier verschillende therapeuten verteld over Typebase. Twee stopten me als cliënt. De andere twee bouwen nu een app ermee."
— Clementine Ryu, Engineer, tussen therapeuten door
"Mijn co-founder vroeg waar de auth staat. Ik zei: 'in een bestand genaamd auth.ts'. Hij heeft sindsdien niet meer tegen me gesproken. Ik neem aan dat hij onder de indruk is."
— Tomás Lindberg, Indie hacker, mogelijk single
"We hebben 14 microservices vervangen door één map. Het DevOps-team gaf een feestje voor me. Het feestje was een vergadering. De vergadering ging over ontslagen."
— Anoniem, om voor de hand liggende redenen
"10/10 zou mijn backend opnieuw een map maken."
— Hannah Pollard, Senior Folder Engineer, zelfbenoemd
---
Geef je AI-agent een backend die hij kan lezen
Het kost ongeveer negentig seconden. Het grootste deel daarvan is npm install.
$ npm i typebase-io && npm i -D typebase-io-cli