DjangoCon US 2024 was held in Durham, North Carolina from September 22–27, 2024. The conference brought together Django contributors, maintainers, and practitioners for talks spanning web development, APIs, database design, and Python ecosystem updates.

UUID Primary Keys in Django — The Status Quo

Django’s built-in UUIDField has long supported UUID primary keys using default=uuid.uuid4. This pattern is well-documented and widely used in Django projects that need globally unique identifiers without auto-increment integers.

Sessions at DjangoCon US 2024 examined the performance characteristics of this approach at scale. The core issue: uuid.uuid4() generates fully random 128-bit values. When used as a primary key in PostgreSQL or MySQL, inserts are spread randomly across the B-tree index, causing frequent page splits and a phenomenon known as index fragmentation. At tens of millions of rows, this degrades write throughput and increases index size compared to sequential keys.

Python 3.13 and the New uuid.uuid7()

A major highlight for Django developers was Python 3.13’s addition of uuid.uuid7() to the standard library. Previously, projects needed third-party packages like uuid6 to generate UUID v7 values. With Python 3.13, the function is available with no additional dependencies.

Speakers demonstrated the new usage pattern:

import uuid
from django.db import models

class MyModel(models.Model):
    id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid7,
        editable=False,
    )

The change from uuid.uuid4 to uuid.uuid7 is a single-token edit, and Django handles the rest: the underlying column type remains uuid, so no schema migration is needed for the database itself — only a Django migration to update the field’s default callable.

Index Performance in PostgreSQL and MySQL

Talks comparing uuid4 and uuid7 defaults measured the difference in index efficiency using pgbench and custom insert benchmarks. Findings presented were consistent with earlier research by Percona:

Practical Migration from UUID v4 to UUID v7

DjangoCon US 2024 sessions provided a concrete migration checklist:

  1. Upgrade to Python 3.13 (or add uuid6 as a dependency for earlier versions)
  2. Update default=uuid.uuid4 to default=uuid.uuid7 on UUID primary key fields
  3. Run python manage.py makemigrations — Django will generate a migration altering the field’s default
  4. Apply the migration — no data transformation occurs; the default only affects new rows
  5. Optionally backfill existing rows if temporal ordering of historical data is required

Frequently asked questions

How do Django projects handle UUID primary keys?

DjangoCon US 2024 included talks on UUID primary key strategies in Django, covering UUIDField, the move from uuid4 to uuid7 as the recommended default, and performance implications for large tables. Django's built-in UUIDField supports any UUID version.

Does Python support UUID v7?

Yes, from Python 3.13 via uuid.uuid7() in the standard library. For Python 3.9–3.12, install the uuid6 package which provides the same interface.

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.

How do I use UUID v7 as a primary key in Django?

With Python 3.13+, use uuid.uuid7 from the standard library as the default for a UUIDField: id = models.UUIDField(primary_key=True, default=uuid.uuid7, editable=False). On earlier Python versions, the uuid6 package provides uuid6.uuid7() as a drop-in. See the Django UUIDField documentation for full details.

Does switching from UUID v4 to UUID v7 require a Django migration?

The column type stays uuid — no schema migration is needed. You only need to update the default callable on the field. Existing rows keep their UUID v4 values; new rows get UUID v7 values. Django's migration framework will detect the field change and generate a migration that alters only the default, not the column type.