with one click
add-database-table
Add a new database table with Drizzle ORM
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Add a new database table with Drizzle ORM
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
| name | Add Database Table |
| description | Add a new database table with Drizzle ORM |
You are helping add a new database table to a Next.js application using Drizzle ORM with PostgreSQL.
apps/web/lib/server/db/schema/Ask the user:
Create a new file in lib/server/db/schema/:
// lib/server/db/schema/[table-name]s.ts
import {
pgTable,
text,
timestamp,
uuid,
boolean,
integer,
varchar,
} from "drizzle-orm/pg-core"
import { createInsertSchema, createSelectSchema } from "drizzle-zod"
import { relations } from "drizzle-orm"
// Define the table
export const [tableName]s = pgTable("[table_name]", {
id: uuid("id").primaryKey().defaultRandom(),
// Add your fields here
// Examples:
// name: text("name").notNull(),
// email: varchar("email", { length: 255 }).notNull().unique(),
// age: integer("age"),
// isActive: boolean("isActive").default(true),
// Timestamps (always include)
createdAt: timestamp("createdAt").notNull().defaultNow(),
updatedAt: timestamp("updatedAt").notNull().defaultNow(),
})
// Define relations (if any)
export const [tableName]sRelations = relations([tableName]s, ({ one, many }) => ({
// Example: many-to-one
// user: one(users, {
// fields: [tableName]s.userId],
// references: [users.id],
// }),
// Example: one-to-many
// posts: many(posts),
}))
// Generate Zod schemas for validation
export const insert[TableName]Schema = createInsertSchema([tableName]s)
export const select[TableName]Schema = createSelectSchema([tableName]s)
// Export TypeScript types
export type [TableName] = typeof [tableName]s.$inferSelect
export type New[TableName] = typeof [tableName]s.$inferInsert
// Text fields
text("field_name") // Unlimited text
varchar("field_name", { length: 255 }) // Variable length (max 255)
// Numbers
integer("field_name") // Integer
serial("field_name") // Auto-increment
real("field_name") // Floating point
// Booleans
boolean("field_name")
// Dates
timestamp("field_name") // Date + time
date("field_name") // Date only
// UUIDs
uuid("field_name")
// JSON
json("field_name") // JSON field
jsonb("field_name") // Binary JSON (faster)
// Not null
.notNull()
// Unique
.unique()
// Default value
.default(value)
.defaultNow() // For timestamps
.defaultRandom() // For UUIDs
// Primary key
.primaryKey()
// Foreign key
.references(() => users.id, { onDelete: "cascade" })
import { users } from "./users"
export const posts = pgTable("post", {
id: uuid("id").primaryKey().defaultRandom(),
title: text("title").notNull(),
content: text("content").notNull(),
// Foreign key to users table
userId: uuid("userId")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
createdAt: timestamp("createdAt").notNull().defaultNow(),
updatedAt: timestamp("updatedAt").notNull().defaultNow(),
})
// Define the relation
export const postsRelations = relations(posts, ({ one }) => ({
user: one(users, {
fields: [posts.userId],
references: [users.id],
}),
}))
Add export to lib/server/db/schema/index.ts:
export * from "./users"
export * from "./posts"
export * from "./[new-table]" // Add this line
Run the migration:
# Push schema changes to database (development)
npm run db:push
# Or generate migration file (production)
npm run db:generate
npm run db:migrate
Show the user how to query the new table:
import { db } from "@/lib/server/db"
import { [tableName]s } from "@/lib/server/db/schema"
import { eq, and, or, gt } from "drizzle-orm"
// Find all
const all = await db.query.[tableName]s.findMany()
// Find one
const one = await db.query.[tableName]s.findFirst({
where: eq([tableName]s.id, id),
})
// With relations
const withRelations = await db.query.[tableName]s.findFirst({
where: eq([tableName]s.id, id),
with: {
relatedTable: true,
},
})
// Insert
const [created] = await db
.insert([tableName]s)
.values({
// field: value,
})
.returning()
// Update
const [updated] = await db
.update([tableName]s)
.set({
// field: value,
updatedAt: new Date(),
})
.where(eq([tableName]s.id, id))
.returning()
// Delete
await db
.delete([tableName]s)
.where(eq([tableName]s.id, id))
The generated Zod schemas can be used for validation:
import { insert[TableName]Schema } from "@/lib/server/db/schema"
// In a server action
export async function create[TableName](data: unknown) {
try {
// Validate with Zod
const validated = insert[TableName]Schema.parse(data)
// Insert into database
const [created] = await db
.insert([tableName]s)
.values(validated)
.returning()
return { success: true, data: created }
} catch (error) {
return { success: false, error: "Validation failed" }
}
}
You can extend the generated schemas:
import { z } from "zod"
export const customInsertSchema = insert[TableName]Schema.extend({
email: z.string().email(),
age: z.number().min(0).max(150),
password: z.string().min(8),
})
// lib/server/db/schema/posts.ts
import { pgTable, text, timestamp, uuid, boolean } from "drizzle-orm/pg-core"
import { createInsertSchema, createSelectSchema } from "drizzle-zod"
import { relations } from "drizzle-orm"
import { users } from "./users"
export const posts = pgTable("post", {
id: uuid("id").primaryKey().defaultRandom(),
title: text("title").notNull(),
content: text("content").notNull(),
slug: text("slug").notNull().unique(),
published: boolean("published").default(false),
// Foreign key
authorId: uuid("authorId")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
createdAt: timestamp("createdAt").notNull().defaultNow(),
updatedAt: timestamp("updatedAt").notNull().defaultNow(),
})
// Relations
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
}))
// Zod schemas
export const insertPostSchema = createInsertSchema(posts)
export const selectPostSchema = createSelectSchema(posts)
// TypeScript types
export type Post = typeof posts.$inferSelect
export type NewPost = typeof posts.$inferInsert
Before completing, ensure:
lib/server/db/schema/schema/index.tsnpm run db:push)Now help the user create their database table!