Photo by JAYAKODY ANTHANAS on Unsplash
Use Drizzle ORM (ver 0.29) π¦ and PostgresJS π step by step with Bun
Warning, this blog is written when using drizzle-orm@^0.29.5
version.
Installation
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
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
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
Migration
In your project's root directory, create environment variables file:
cp .env.example .env
.env.example
:
# DEV | PROD | STG
ENV=
DATABASE_URL=
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:
postgres://{user}:{password}@{hostname}:{port}/{database-name}
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)
}
process.exit(0)
}
main()
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
src/db/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)
Seed
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. π')
// DONE
process.exit(0)
To run seeding:
bun seed
Commands Summary
bun gen
bun migrate
bun seed
Troubleshooting
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: https://github.com/loclv/bun-monorepo.