Plugins

Timestamps

Automatic createdAt / updatedAt management for better-drizzle, with app-managed and database-managed modes.

@better-drizzle/timestamps keeps timestamp handling out of your services. It can manage timestamps in application code, or stay out of the way when your database already owns them via defaults, generated columns, or triggers.

Install

npm install @better-drizzle/timestamps
pnpm add @better-drizzle/timestamps
yarn add @better-drizzle/timestamps
bun add @better-drizzle/timestamps

Usage

import { better } from 'better-drizzle';
import { timestamps } from '@better-drizzle/timestamps';

const client = better(db, {
	schema,
	plugins: [
		timestamps({
			createdAt: 'createdAt',
			updatedAt: 'updatedAt',
			mode: 'app',
		}),
	],
});

Every option is optional. timestamps() with no arguments uses the defaults:

  • createdAt: 'createdAt'
  • updatedAt: 'updatedAt'
  • mode: 'app'

Modes

mode: 'app'

The plugin fills timestamp columns before the database call:

OperationBehavior
createsets createdAt and updatedAt
createManysets both for each row
updaterefreshes updatedAt
upsertsets both on the create payload, refreshes updatedAt on update
const post = await client.posts.create({
	data: { title: 'Hello' },
});

post.createdAt; // Date
post.updatedAt; // Date

mode: 'database'

The plugin becomes a no-op — use it when the database owns timestamps (column defaults like DEFAULT now(), ON UPDATE, triggers, or generated values):

timestamps({ mode: 'database' });

In this mode it adds effectively zero runtime behavior; the database stays the source of truth.

Custom column names

timestamps({
	createdAt: 'created_at',
	updatedAt: 'updated_at',
});

Behavior details

  • Models missing the configured columns are skipped automatically.
  • It only mutates write payloads — reads, filters, and result shapes are untouched.
  • Works the same for single writes, batch writes, and upserts.

On this page