Use Drizzle ORM (ver 0.29) πŸ’¦ and PostgresJS 🐘 step by step with Bun


4 min read

Warning, this blog is written when using drizzle-orm@^0.29.5 version.


bun add drizzle-orm@^0.29.5 postgres
bun add -D drizzle-kit@^0.20.18

Define the schema

cd src
mkdir db
cd db
mkdir schema
cd schema
touch products.ts


import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core'

export const products = pgTable('products', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  description: text('description'),
  price: integer('price'),

Back to the project root directory:

touch drizzle.config.ts


import type { Config } from 'drizzle-kit'

export default {
  schema: './src/db/schema/products.ts',
  out: './drizzle',
} satisfies Config

Add the script to the package.json:

  "scripts": {
    "gen": "drizzle-kit generate:pg"

To generate the SQL migration files:

bun gen

Generated command's output is below.

[βœ“] Your SQL migration file ➜ drizzle/0000_talented_smasher.sql πŸš€

Troubleshooting when generating the SQL migration

If you have an error when generating the SQL migration:

Error: Cannot find module 'node:process'
Require stack:
- ~/bun-monorepo/node_modules/drizzle-kit/bin.cjs

Please use the latest version of the Node.js:

fnm use 20


In your project's root directory, create environment variables file:

cp .env.example .env



We need to specify the database connection URL for the development.

For example, if you run PostgreSQL server on localhost using the brew command:

brew services start postgresql
# => Successfully started `postgresql@14`

PostgreSQL URL's format is:


In this case, hostname and port are localhost:5432.

bun run env | grep ENV
bun run env | grep DATABASE

In your project's root directory, create a migrate.ts file:

touch migrate.ts
import { migrate } from 'drizzle-orm/postgres-js/migrator'
import postgres from 'postgres'
import { drizzle } from 'drizzle-orm/postgres-js'

console.log('Start migration! πŸ€')

if (!process.env.DATABASE_URL) {
  throw new Error('Please specify a DATABASE_URL environment variable! 🚧')

const databaseUrl = drizzle(
  postgres(`${process.env.DATABASE_URL}`, {
    ssl: process.env.ENV === 'PROD' || process.env.ENV === 'STG' ? 'require' : false,
    max: 1,

const main = async () => {
  try {
    await migrate(databaseUrl, { migrationsFolder: 'drizzle' })
    console.log('Migration complete! 🌟')
  } catch (error) {
    console.log('🚫 Err: ', error)



Add migration scripts to your package.json:

  "scripts": {
    "migrate": "bun run migrate.ts"

To run migrations:

bun migrate

Troubleshooting when running migration

If you have an error when running migration:

Start migration! πŸ€
🚫 Err:  ECONNREFUSED: Failed to connect
 syscall: "connect"

May be you need to start the PostgreSQL server:

# MacOS:
brew services start postgresql
# ==> Successfully started `postgresql@14` (label: homebrew.mxcl.postgresql@14)

Create a DB instance for query purposes

cd src/db
touch index.ts


import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'

if (!process.env.DATABASE_URL) {
  throw new Error('Please specify a DATABASE_URL environment variable! 🚧')

 * for query purposes
const queryClient = postgres(process.env.DATABASE_URL)
export const db = drizzle(queryClient)


Now that we have a database, let's add some data to it. Create a seed.ts file with the following contents.

touch seed.ts
import { db } from './src/db'
import { products } from './src/db/schema/products'

await db.insert(products).values([
    id: 1,
    name: 'Product A',
    description: 'A description',
    price: 11,
    id: 2,
    name: 'Product B',
    description: 'B description',
    price: 11,
    id: 3,
    name: 'Product C',
    description: 'C description',
    price: 11,

console.log('Seeding complete. 🌟')


To run seeding:

bun seed

Commands Summary

bun gen
bun migrate
bun seed


When you see an error about tsconfig.json, you can use the configuration below:

  "compilerOptions": {
    "target": "esnext",
    "module": "ESNext",
    "lib": ["DOM"],
    "composite": false,
    "declaration": true,
    "declarationMap": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "inlineSources": false,
    "isolatedModules": true,
    "moduleResolution": "node",
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "preserveWatchOutput": true,
    "skipLibCheck": true,
    "strict": true
  "include": ["."],
  "exclude": ["dist", "build", "node_modules"]

You also can use the runnable project: