Skip to content
VibORM
Esc
navigateopen⌘Jpreview
On this page

Quick Start

Build your first VibORM schema in 5 minutes with a simple blog example featuring users and posts

1. Define Your Schema

Create a schema.ts file with your model definitions:

import { s } from "viborm";

// User model
export const user = s.model({
  id: s.string().id().ulid(),
  email: s.string().unique(),
  name: s.string(),
  createdAt: s.dateTime().default(() => new Date()),
  posts: s.oneToMany(() => post),
});

// Post model
export const post = s.model({
  id: s.string().id().ulid(),
  title: s.string(),
  content: s.string().nullable(),
  published: s.boolean().default(false),
  authorId: s.string(),
  author: s.manyToOne(() => user)
    .fields("authorId")
    .references("id"),
  createdAt: s.dateTime().default(() => new Date()),
});

2. Create the Client

Initialize your database client with your preferred database:

import { createClient } from "viborm/postgres";
import * as schema from "./schema";

export const client = createClient({
  schema,
  databaseUrl: process.env.DATABASE_URL,
});
import { createClient } from "viborm/pg";
import * as schema from "./schema";

export const client = createClient({
  schema,
  databaseUrl: process.env.DATABASE_URL,
});
import { createClient } from "viborm/sqlite3";
import * as schema from "./schema";

export const client = createClient({
  schema,
  dataDir: "./data.db",
});
import { createClient } from "viborm/pglite";
import * as schema from "./schema";

export const client = createClient({
  schema,
  dataDir: "./data",
});

3. Create the Database Tables

Your database is still empty. Create a viborm.config.ts in your project root and push the schema:

import { defineConfig } from "viborm/config";
import { client } from "./src/db/client";

export default defineConfig({ client });
bun viborm push

push syncs your models straight to the database without migration files — see Push for details and Configuration for config options.

4. Query Your Data

Now you can use the fully typed client:

import { client } from "./db/client";

// Create a user
const newUser = await client.user.create({
  data: {
    email: "alice@example.com",
    name: "Alice",
  },
});

// Create a post for the user
const newPost = await client.post.create({
  data: {
    title: "My First Post",
    content: "Hello, VibORM!",
    authorId: newUser.id,
  },
});

// Find users with their posts
const users = await client.user.findMany({
  where: {
    email: { contains: "@example.com" },
  },
  include: {
    posts: {
      where: { published: true },
      orderBy: { createdAt: "desc" },
    },
  },
});

// Update a post
await client.post.update({
  where: { id: newPost.id },
  data: { published: true },
});

// Delete unpublished posts
await client.post.deleteMany({
  where: { published: false },
});

5. Type Safety in Action

VibORM provides full type inference:

// ✅ TypeScript knows the exact shape
const user = await client.user.findUnique({
  where: { email: "alice@example.com" },
  select: { id: true, name: true },
});
// Type: { id: string; name: string } | null

// ❌ TypeScript catches errors at compile time
await client.user.create({
  data: {
    email: "bob@example.com",
    // Error: 'name' is required
  },
});

// ❌ Invalid field names are rejected
await client.user.findMany({
  where: { invalidField: "value" }, // Error: 'invalidField' does not exist
});

Next Steps

Was this page helpful?