Bun
Bun is the recommended runtime for Drizzle DuckDB. It provides excellent performance and native TypeScript support.
Installation
bun add @leonardovida-md/drizzle-neo-duckdb @duckdb/node-api
Basic Usage
// db.ts
import { DuckDBInstance } from '@duckdb/node-api';
import { drizzle } from '@leonardovida-md/drizzle-neo-duckdb';
import * as schema from './schema';
const instance = await DuckDBInstance.create('./app.duckdb');
const connection = await instance.connect();
export const db = drizzle(connection, { schema });
Run with:
bun run db.ts
Why Bun?
Native TypeScript
No compilation step needed. Bun runs TypeScript directly:
bun run src/index.ts
Fast Startup
Bun’s fast startup makes it ideal for scripts and serverless:
# Run migrations
bun run scripts/migrate.ts
# Run introspection
bun run scripts/introspect.ts
Native Module Support
@duckdb/node-api is a native Node.js addon. Bun handles it seamlessly.
Project Setup
package.json
{
"name": "my-duckdb-app",
"type": "module",
"scripts": {
"dev": "bun run --watch src/index.ts",
"start": "bun run src/index.ts",
"db:migrate": "bun run scripts/migrate.ts",
"db:introspect": "bun run scripts/introspect.ts"
},
"dependencies": {
"@duckdb/node-api": "^1.0.0",
"@leonardovida-md/drizzle-neo-duckdb": "^1.0.0",
"drizzle-orm": "^0.30.0"
},
"devDependencies": {
"drizzle-kit": "^0.20.0"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"types": ["bun-types"]
}
}
Scripts
Migration Script
// scripts/migrate.ts
import { DuckDBInstance } from '@duckdb/node-api';
import { drizzle, migrate } from '@leonardovida-md/drizzle-neo-duckdb';
async function main() {
const instance = await DuckDBInstance.create('./app.duckdb');
const connection = await instance.connect();
const db = drizzle(connection);
console.log('Running migrations...');
await migrate(db, './drizzle');
console.log('Done!');
connection.closeSync();
}
main().catch(console.error);
Introspection Script
// scripts/introspect.ts
import { DuckDBInstance } from '@duckdb/node-api';
import { drizzle, introspect } from '@leonardovida-md/drizzle-neo-duckdb';
import { writeFileSync } from 'fs';
async function main() {
const instance = await DuckDBInstance.create('./app.duckdb');
const connection = await instance.connect();
const db = drizzle(connection);
const result = await introspect(db);
writeFileSync('./src/db/schema.ts', result.files.schemaTs);
console.log('Schema written to ./src/db/schema.ts');
connection.closeSync();
}
main().catch(console.error);
Testing with Bun
Bun has a built-in test runner:
// tests/db.test.ts
import { describe, it, expect, beforeAll, afterAll } from 'bun:test';
import { DuckDBInstance } from '@duckdb/node-api';
import { drizzle } from '@leonardovida-md/drizzle-neo-duckdb';
import { sql } from 'drizzle-orm';
let instance: DuckDBInstance;
let connection: any;
let db: any;
beforeAll(async () => {
instance = await DuckDBInstance.create(':memory:');
connection = await instance.connect();
db = drizzle(connection);
await db.execute(sql`
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
)
`);
});
afterAll(() => {
connection.closeSync();
});
describe('database', () => {
it('should insert and query users', async () => {
await db.execute(sql`INSERT INTO users VALUES (1, 'Alice')`);
const result = await db.execute(sql`SELECT * FROM users`);
expect(result).toHaveLength(1);
expect(result[0].name).toBe('Alice');
});
});
Run tests:
bun test
Environment Variables
Bun loads .env files automatically:
# .env
MOTHERDUCK_TOKEN=your_token_here
DATABASE_PATH=./data/app.duckdb
const token = process.env.MOTHERDUCK_TOKEN; // Available without dotenv
Watch Mode
For development, use watch mode:
bun run --watch src/index.ts
Production
Build for production (optional):
bun build src/index.ts --outdir ./dist --target node
Or run directly in production:
NODE_ENV=production bun run src/index.ts
See Also
- Installation - Package setup
- Quick Start - First application
- Examples - Complete examples