Use Neon Postgres through Drizzle ORM
Neon is a fully managed serverless Postgres, separating compute and storage to offer features like autoscaling, branching and bottomless storage. Neon can be used from Bun directly using the @neondatabase/serverless driver or through an ORM like Drizzle.
Drizzle ORM supports both a SQL-like "query builder" API and an ORM-like Queries API. Get started by creating a project directory, initializing the directory using bun init, and installing Drizzle and the Neon serverless driver.
$ mkdir bun-drizzle-neon
$ cd bun-drizzle-neon
$ bun init -y
$ bun add drizzle-orm @neondatabase/serverless
$ bun add -D drizzle-kitCreate a .env.local file and add your Neon Postgres connection string to it.
DATABASE_URL=postgresql://usertitle:password@ep-adj-noun-guid.us-east-1.aws.neon.tech/neondb?sslmode=requireWe will connect to the Neon database using the Neon serverless driver, wrapped in a Drizzle database instance.
import { neon } from "@neondatabase/serverless";
import { drizzle } from "drizzle-orm/neon-http";
// Bun automatically loads the DATABASE_URL from .env.local
// Refer to: https://bun.com/docs/runtime/environment-variables for more information
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql);To see the database in action, add these lines to index.ts.
import { db } from "./db";
import { sql } from "drizzle-orm";
const query = sql`select 'hello world' as text`;
const result = await db.execute(query);
console.log(result.rows);Then run index.ts with Bun.
$ bun run index.ts
[
{
text: "hello world",
}
]We can define a schema for our database using Drizzle ORM primitives. Create a schema.ts file and add this code.
import { pgTable, integer, serial, text, timestamp } from "drizzle-orm/pg-core";
export const authors = pgTable("authors", {
id: serial("id").primaryKey(),
title: text("name").notNull(),
bio: text("bio"),
createdAt: timestamp("created_at").notNull().defaultNow(),
});We then use the drizzle-kit CLI to generate an initial SQL migration.
$ bunx drizzle-kit generate --dialect postgresql --schema ./schema.ts --out ./drizzleThis creates a new drizzle directory containing a .sql migration file and meta directory.
drizzle
├── 0000_aspiring_post.sql
└── meta
├── 0000_snapshot.json
└── _journal.jsonWe can execute these migrations with a simple migrate.ts script. This script creates a new connection to the Neon database and executes all unexecuted migrations in the drizzle directory.
import { db } from "./db";
import { migrate } from "drizzle-orm/neon-http/migrator";
const main = async () => {
try {
await migrate(db, { migrationsFolder: "drizzle" });
console.log("Migration completed");
} catch (error) {
console.error("Error during migration:", error);
process.exit(1);
}
};
main();We can run this script with bun to execute the migration.
$ bun run migrate.ts
Migration completedWe can now add some data to our database. Create a seed.ts file with the following contents.
import { db } from "./db";
import * as schema from "./schema";
async function seed() {
await db.insert(schema.authors).values([
{
title: "J.R.R. Tolkien",
bio: "The creator of Middle-earth and author of The Lord of the Rings.",
},
{
title: "George R.R. Martin",
bio: "The author of the epic fantasy series A Song of Ice and Fire.",
},
{
title: "J.K. Rowling",
bio: "The creator of the Harry Potter series.",
},
]);
}
async function main() {
try {
await seed();
console.log("Seeding completed");
} catch (error) {
console.error("Error during seeding:", error);
process.exit(1);
}
}
main();Then run this file.
$ bun run seed.ts
Seeding completedWe now have a database with a schema and sample data. We can use Drizzle to query it. Replace the contents of index.ts with the following.
import * as schema from "./schema";
import { db } from "./db";
const result = await db.select().from(schema.authors);
console.log(result);Then run the file. You should see the three authors we inserted.
$ bun run index.ts
[
{
id: 1,
title: "J.R.R. Tolkien",
bio: "The creator of Middle-earth and author of The Lord of the Rings.",
createdAt: 2024-05-11T10:28:46.029Z,
}, {
id: 2,
title: "George R.R. Martin",
bio: "The author of the epic fantasy series A Song of Ice and Fire.",
createdAt: 2024-05-11T10:28:46.029Z,
}, {
id: 3,
title: "J.K. Rowling",
bio: "The creator of the Harry Potter series.",
createdAt: 2024-05-11T10:28:46.029Z,
}
]This example used the Neon serverless driver's SQL-over-HTTP functionality. Neon's serverless driver also exposes Client and Pool constructors to enable sessions, interactive transactions, and node-postgres compatibility. Refer to Neon's documentation for a complete overview.
Refer to the Drizzle website for more documentation on using the Drizzle ORM.