Skip to content

Database ​

Viseed CMS uses PostgreSQL with Drizzle ORM for type-safe database access. The connection is managed via Bun's built-in SQL driver (bun:sql), so no separate PostgreSQL client package is needed.

PostgreSQL only

Only PostgreSQL is supported. Other databases (MySQL, SQLite, etc.) are not compatible.


Connection ​

Provide your connection string via DATABASE_URL or directly in the config:

typescript
const cms = createCMS({
  db: {
    driver: 'postgres',
    url: process.env.DATABASE_URL ?? 'postgresql://localhost:5432/hana',
  },
})

Connection string format:

postgresql://[user]:[password]@[host]:[port]/[database]

For managed databases with SSL (e.g. DigitalOcean, Supabase):

postgresql://user:pass@host:5432/db?sslmode=verify-full&sslrootcert=./ca-certificate.crt

Schema Management ​

Use the viseed db commands to manage your database schema. The CLI automatically discovers the core schema plus schemas from all installed viseed-plugin-* packages.

Development ​

Push your current schema directly to the database. This is the fastest way to iterate during development — no migration files are generated.

bash
bunx viseed db push

WARNING

db push may drop columns or alter tables to match the schema. Do not use in production.

Production ​

Generate SQL migration files that can be reviewed and committed to source control:

bash
bunx viseed db generate

Apply pending migrations to the database:

bash
bunx viseed db migrate

The recommended production workflow:

bash
# 1. Generate migration files (in CI or locally)
bunx viseed db generate

# 2. Review generated files in drizzle/
git add drizzle/
git commit -m "feat: add migration"

# 3. Apply migrations on the server
bunx viseed db migrate

Core Tables ​

The following tables are created by Viseed CMS core:

TableDescription
sitesSite definitions (supports multi-site)
site_domainsDomain mapping per site
usersUser accounts
user_site_rolesRole assignments per user per site
sessionsAuth sessions
installed_pluginsPlugin registry (enabled plugins per site)
installed_themesTheme registry (installed themes per site)
theme_stateActive theme state per site
media_filesUploaded media files

Plugin tables are prefixed by the plugin name, e.g. blog_posts, blog_categories, menu_items.


Schema Merging ​

Plugins contribute their own Drizzle table definitions. All plugin schemas are merged with the core schema at startup:

typescript
// Internally handled by createCMS — you don't call this directly
const finalSchema = mergeSchemas(coreSchema, ...pluginSchemas)

When running viseed db commands, the CLI scans your package.json for viseed-plugin-* dependencies and auto-generates a schema barrel file to feed into drizzle-kit.


Custom Schemas ​

If your application defines additional Drizzle tables beyond what plugins provide, register them in viseed.config.ts at the project root:

typescript
// viseed.config.ts
export default {
  extraSchemas: ['./src/schema.ts'],
}

These will be included when running any viseed db command.

Example custom schema:

typescript
// src/schema.ts
import { pgTable, text, timestamp } from 'drizzle-orm/pg-core'

export const mySchema = {
  subscriptions: pgTable('subscriptions', {
    id: text('id').primaryKey(),
    email: text('email').notNull(),
    createdAt: timestamp('created_at').defaultNow(),
  }),
}