Multi-Database Support
Multi-Database Support allows you to use any database with Flowfull through Kysely ORM. Switch databases without changing your code.
Supported Databases
Flowfull supports multiple database types:
| Database | Type | Use Case |
|---|---|---|
| PostgreSQL | Traditional | Production, complex queries |
| MySQL | Traditional | Production, compatibility |
| LibSQL/Turso | Serverless | Edge deployments, low latency |
| Neon | Serverless | Serverless Postgres |
| PlanetScale | Serverless | Serverless MySQL |
Configuration
PostgreSQL
env
DATABASE_TYPE=postgresql
DATABASE_URL=postgresql://user:password@localhost:5432/mydbMySQL
env
DATABASE_TYPE=mysql
DATABASE_URL=mysql://user:password@localhost:3306/mydbLibSQL/Turso
env
DATABASE_TYPE=libsql
DATABASE_URL=libsql://your-database.turso.io
DATABASE_AUTH_TOKEN=your-auth-tokenNeon (Serverless Postgres)
env
DATABASE_TYPE=postgresql
DATABASE_URL=postgresql://user:password@ep-xxx.neon.tech/mydb?sslmode=requirePlanetScale (Serverless MySQL)
env
DATABASE_TYPE=mysql
DATABASE_URL=mysql://user:password@aws.connect.psdb.cloud/mydb?ssl={"rejectUnauthorized":true}Usage
The same code works with all databases:
typescript
import { db } from './lib/database';
// Query works with any database
const users = await db
.selectFrom('users')
.where('email', '=', 'user@example.com')
.selectAll()
.execute();
// Insert works with any database
await db
.insertInto('users')
.values({
id: nanoid(),
email: 'user@example.com',
name: 'John Doe'
})
.execute();
// Update works with any database
await db
.updateTable('users')
.set({ name: 'Jane Doe' })
.where('id', '=', userId)
.execute();
// Delete works with any database
await db
.deleteFrom('users')
.where('id', '=', userId)
.execute();Kysely ORM
Flowfull uses Kysely for database abstraction:
Benefits
- ✅ Type-safe queries
- ✅ Works with multiple databases
- ✅ No code generation
- ✅ Excellent TypeScript support
- ✅ Lightweight and fast
Example
typescript
// Type-safe query
const user = await db
.selectFrom('users')
.where('id', '=', userId)
.select(['id', 'email', 'name'])
.executeTakeFirst();
// TypeScript knows the shape of `user`
console.log(user.email); // ✅ Type-safe
console.log(user.invalid); // ❌ TypeScript errorMigrations
Migrations work the same across all databases:
typescript
// migrations/001_create_users.ts
import { Kysely } from 'kysely';
export async function up(db: Kysely<any>): Promise<void> {
await db.schema
.createTable('users')
.addColumn('id', 'varchar(255)', (col) => col.primaryKey())
.addColumn('email', 'varchar(255)', (col) => col.notNull().unique())
.addColumn('name', 'varchar(255)', (col) => col.notNull())
.addColumn('created_at', 'timestamp', (col) => col.notNull())
.execute();
}
export async function down(db: Kysely<any>): Promise<void> {
await db.schema.dropTable('users').execute();
}Run migrations:
bash
bun run migrateSwitching Databases
To switch databases, just change the environment variables:
env
# From PostgreSQL
DATABASE_TYPE=postgresql
DATABASE_URL=postgresql://localhost:5432/mydb
# To MySQL
DATABASE_TYPE=mysql
DATABASE_URL=mysql://localhost:3306/mydb
# To LibSQL/Turso
DATABASE_TYPE=libsql
DATABASE_URL=libsql://your-database.turso.io
DATABASE_AUTH_TOKEN=your-tokenNo code changes required! 🎉
Best Practices
✅ Do
- Use PostgreSQL for complex queries
- Use LibSQL/Turso for edge deployments
- Use Neon/PlanetScale for serverless
- Write database-agnostic queries
- Test with multiple databases
❌ Don't
- Use database-specific SQL
- Hardcode database type
- Skip migrations
- Forget to backup data
- Mix database types in production
Database-Specific Features
PostgreSQL
typescript
// JSON queries
const users = await db
.selectFrom('users')
.where('metadata->email_verified', '=', 'true')
.selectAll()
.execute();
// Full-text search
const results = await db
.selectFrom('posts')
.where(sql`to_tsvector(title) @@ to_tsquery(${query})`)
.selectAll()
.execute();MySQL
typescript
// JSON queries
const users = await db
.selectFrom('users')
.where(sql`JSON_EXTRACT(metadata, '$.email_verified')`, '=', 'true')
.selectAll()
.execute();LibSQL/Turso
typescript
// Edge-optimized queries
const users = await db
.selectFrom('users')
.where('region', '=', 'us-east')
.selectAll()
.execute();Connection Pooling
PostgreSQL/MySQL
typescript
import { Pool } from 'pg';
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20, // Max connections
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});LibSQL/Turso
typescript
import { createClient } from '@libsql/client';
const client = createClient({
url: process.env.DATABASE_URL,
authToken: process.env.DATABASE_AUTH_TOKEN,
});Next Steps
- Database Setup Guide - Detailed setup instructions
- Environment Config - Configure databases
- Deployment - Deploy with databases
Need Help?
- 🌐 Notside.com - Professional database architecture
- 📧 Email: contact@notside.com