UUID v7 support has moved from experimental to mainstream across the major ORMs. In 2025 and 2026, Prisma, Drizzle ORM, GORM, and SQLAlchemy all shipped stable UUID v7 defaults. This article covers the current state of each ORM — what it provides, what version is required, and how to configure it.

Prisma

Prisma added uuid(7) as a valid argument to @default() in version 5.x. Prior to this, teams used @default(uuid()) which generates v4.

model User {
  id        String   @id @default(uuid(7))
  email     String   @unique
  createdAt DateTime @default(now())
}

The uuid(7) function generates the value at the application layer (in the Prisma runtime), not in the database. This means the default fires when Prisma inserts a row without an explicit id — it does not set a SQL-level default. If you insert rows via raw SQL or another client, those rows will not automatically get v7 values unless you also set a database-level default.

To get a database-level default in PostgreSQL 18, combine Prisma’s schema with a SQL migration:

-- Set database-level default for rows inserted outside Prisma
ALTER TABLE "User" ALTER COLUMN id SET DEFAULT uuidv7();

Prisma will ignore this when generating rows itself (its own default takes precedence), but raw inserts will use the database default.

Drizzle ORM

Drizzle supports UUID v7 via application-layer defaults using $defaultFn:

import { v7 as uuidv7 } from 'uuid';
import { pgTable, uuid } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: uuid('id').primaryKey().$defaultFn(() => uuidv7()),
  email: text('email').notNull(),
});

For PostgreSQL 18, you can also rely on the database default and skip the application-layer default entirely:

export const users = pgTable('users', {
  id: uuid('id').primaryKey().default(sql`uuidv7()`),
  email: text('email').notNull(),
});

The sql tagged template passes the expression through to the database as a raw SQL default, so Drizzle generates DEFAULT uuidv7() in the DDL. This is the cleanest option on PostgreSQL 18 — one source of truth, no application-layer dependency on the uuid package.

GORM

GORM uses BeforeCreate hooks for UUID generation. The google/uuid package supports v7 via uuid.NewV7() since version 1.6.

import (
  "github.com/google/uuid"
  "gorm.io/gorm"
)

type Base struct {
  ID string `gorm:"primarykey;type:uuid"`
}

func (b *Base) BeforeCreate(tx *gorm.DB) error {
  id, err := uuid.NewV7()
  if err != nil {
    return err
  }
  b.ID = id.String()
  return nil
}

type User struct {
  Base
  Email string `gorm:"uniqueIndex"`
}

Since uuid.NewV7() returns an error (it reads from the system entropy source), the BeforeCreate hook must handle it. In practice this error is almost never non-nil, but the signature requires it.

For PostgreSQL 18, you can also delegate to the database by setting the column tag to use a database default:

type User struct {
  ID    string `gorm:"primarykey;type:uuid;default:uuidv7()"`
  Email string `gorm:"uniqueIndex"`
}

With default:uuidv7(), GORM will not generate the ID in Go — it relies on PostgreSQL to fill it. You then need to read the ID back after insert, which GORM does automatically via RETURNING id.

SQLAlchemy

SQLAlchemy 2.x supports UUID v7 via Python 3.13’s uuid.uuid7() or the uuid6 backport. The Uuid type in SQLAlchemy 2 handles both string and native UUID storage.

import uuid
from sqlalchemy import String
from sqlalchemy.orm import DeclarativeBase, mapped_column, Mapped

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "users"

    id: Mapped[str] = mapped_column(
        String(36),
        primary_key=True,
        default=uuid.uuid7,  # Python 3.13+
    )
    email: Mapped[str] = mapped_column(unique=True)

For Python 3.9–3.12, replace uuid.uuid7 with uuid6.uuid7 from the uuid6 package:

import uuid6
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=uuid6.uuid7)

For PostgreSQL 18, use the server default instead:

from sqlalchemy import text

id: Mapped[str] = mapped_column(
    String(36),
    primary_key=True,
    server_default=text("uuidv7()"),
)

server_default maps to a SQL DEFAULT expression, so the value is generated by the database. SQLAlchemy reads it back via RETURNING.

Which approach to choose

ScenarioRecommendation
PostgreSQL 18, any ORMUse server_default=uuidv7() — single source of truth
PostgreSQL 13–17, any ORMUse application-layer default via the uuid library
Mixed inserts (ORM + raw SQL)Database-level default is safer — covers all insert paths
Non-PostgreSQL databasesApplication-layer only — no native function available

The key principle: if all inserts go through the ORM, application-layer generation is fine. If anything inserts directly to the database — migrations, seed scripts, other services — a database-level default is more reliable.

Further reading

Frequently asked questions

Should UUID v7 be generated in the application or the database?

Both approaches work. Application-layer generation (using a library like the uuid npm package or Python's uuid.uuid7()) works across all database versions. Database-level generation (PostgreSQL 18's uuidv7() function as a column default) is more reliable when multiple clients or raw SQL can insert rows, since every insert path gets a v7 value automatically.

Does PostgreSQL 18 support UUID v7 natively?

Yes. PostgreSQL 18 ships a built-in uuidv7() function that generates RFC 9562-compliant UUID v7 values directly in SQL — no extensions or application-level generation required. The values store in the existing uuid column type unchanged.

What column type should I use to store a UUID in a database?

Use the native type where one exists — uuid in PostgreSQL, uniqueidentifier in SQL Server. In MySQL use BINARY(16) and store raw bytes. Avoid VARCHAR(36): it costs 36 bytes per row versus 16 for binary and makes every comparison a string operation.

Does Prisma support UUID v7?

Yes. Prisma added @default(uuid(7)) in version 5.x, generating UUID v7 values at the application layer via the @prisma/uuid package. The id field uses the standard String type and maps to uuid in PostgreSQL. See the Prisma docs for the exact release that introduced the uuid(7) function.

Does Drizzle ORM support UUID v7?

Yes. Drizzle added a uuid('column_name').defaultRandom() shorthand and explicit $defaultFn(() => uuidv7()) support for UUID v7 application-level defaults. The column maps to the PostgreSQL uuid type. For databases without a native uuid type, Drizzle stores it as varchar(36).