← Back

How to install Drizzle Postgres with Nuxt 3

This guide is for setting up a new app with Nuxt 3 and adding a Postgres Database with Drizzle ORM + Kit for migrations to it. Highly opinionated – that's just the setup I find working for multiple projects. Let me know if you miss something!

Let's start by installing

  • Nuxt 3

  • Drizzle ORM + Drizzle Kit

  • Postgres.js (not pg)

Install Nuxt

pnpm dlx nuxi@latest init my-nuxt-drizzle-project

Install Packages

pnpm add drizzle-orm postgres @paralleldrive/cuid2
pnpm add -D drizzle-kit

Create .env file

Create a .env file in project root with the following content. The url may vary.

DATABASE_URL="postgres://username:password@ip:port/postgres"

Add Drizzle ORM config

Create the directory /server/db and add the following files:

/server/db/schema.ts, this is just an example schema to get started. You can modify this to your needs before continuing.

import { pgTable, timestamp, text } from 'drizzle-orm/pg-core'
import { createId } from '@paralleldrive/cuid2'

export const post = pgTable('post', {
	id: text().primaryKey().$defaultFn(createId),
	title: text().notNull(),
	slug: text().notNull(),
	content: text(),
	createdAt: timestamp({ withTimezone: true }).defaultNow().notNull(),
	updatedAt: timestamp({ withTimezone: true }).defaultNow().notNull(),
})

Add Drizzle Server Utility

Create a new file for the Drizzle DB utility which is used to query your database inside API endpoints. Create the file /server/utils/db.ts

import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'
import * as schema from '../db/schema'

const queryClient = postgres(process.env.DATABASE_URL || '', {
	prepare: false,
})

export const db = drizzle(queryClient, { schema })

Add Drizzle-Kit config

Add the drizzle.config.ts file to your project root.

import { defineConfig } from 'drizzle-kit'

export default defineConfig({
	dialect: 'postgresql',
	schema: './server/db/schema.ts',
	out: './server/db/migrations',
	dbCredentials: {
		url: process.env.DATABASE_URL || '',
	},
})

Add script to package.json

Add two new scripts.

  • db:generate is to generate migration files for you

  • db:migrate is to migrate newly generated migration files to your database (optional)

{
	"name": "nuxt-app",
	"private": true,
	"type": "module",
	"scripts": {
		// ...
		"db:generate": "drizzle-kit generate",
		"db:migrate": "drizzle-kit migrate"
	},
}

If you want another strategy, check out Drizzle Migration Docs. For example, if you want to apply a migration as soon as your Dev Server/App starts:

/server/plugins/migrations.ts

import { migrate } from 'drizzle-orm/postgres-js/migrator'
import { db } from '../utils/db'

export default defineNitroPlugin(async () => {
	try {
		await migrate(db, {
			migrationsFolder: './db/migrations',
		})

		console.info('[server/plugins/migrations.ts] Migration done ✨')
	} catch (error) {
		console.error('[server/plugins/migrations.ts] Migration failed')
		console.error(error)
	}
})

Migrate first time

Now hit pnpm db:generate, you should see a migration file alongside with some others being generated in your /server/db/migrations folder.

Hit pnpm db:migrate (or use your migration strategy) to apply your new schema to the database.


Congrats! 🚀 You now have a very simple Drizzle ORM + Kit setup with Nuxt 3. If you now want to install Better-Auth as a next step, check out my blog post about that.