# How to Add Mixins Like UUIDMixin, TimestampMixin, and SoftDeleteMixin to FastAPI Models

> Easily add UUIDMixin, TimestampMixin, and SoftDeleteMixin to your FastAPI models by importing and inheriting from benavlabs/fastapi-boilerplate core models. Streamline your development.

- Repository: [Benav Labs/fastapi-boilerplate](https://github.com/benavlabs/fastapi-boilerplate)
- Tags: how-to-guide
- Published: 2026-02-26

---

**In the benavlabs/fastapi-boilerplate repository, you add mixins to SQLAlchemy models by importing `UUIDMixin`, `TimestampMixin`, and `SoftDeleteMixin` from [`src/app/core/db/models.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/db/models.py) and including them in your class inheritance list alongside the declarative `Base`.**

The benavlabs/fastapi-boilerplate project implements modern SQLAlchemy 2.0 dataclass-style declarative models that inherit from a common `Base` defined in [`src/app/core/db/database.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/db/database.py) (lines 10-14). Instead of repeating column definitions for UUID primary keys, automatic timestamps, and soft-delete flags across every model, the boilerplate provides reusable mixins that inject these columns automatically.

## What the Built-in Mixins Provide

The mixin module at [`src/app/core/db/models.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/db/models.py) (lines 10-28) contains three declarative mixins designed for common audit and identification patterns.

### UUIDMixin

**`UUIDMixin`** adds a `uuid` column that serves as a unique identifier using the UUIDv7 standard. According to the source code at lines 10-13, it generates the UUID via `uuid7()` in Python while setting a server-side default of `gen_random_uuid()` for database inserts.

```python

# From src/app/core/db/models.py

class UUIDMixin:
    uuid: Mapped[uuid_pkg.UUID] = mapped_column(
        UUID(as_uuid=True), 
        unique=True, 
        default_factory=uuid7, 
        server_default=text("gen_random_uuid()")
    )

```

### TimestampMixin

**`TimestampMixin`** automates `created_at` and `updated_at` tracking. As implemented at lines 16-22, it uses `datetime.now(UTC)` for Python-side defaults and `current_timestamp(0)` for the database defaults, ensuring `updated_at` refreshes on every modification.

```python

# From src/app/core/db/models.py

class TimestampMixin:
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), 
        default_factory=lambda: datetime.now(UTC), 
        server_default=text("current_timestamp(0)")
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), 
        default_factory=lambda: datetime.now(UTC), 
        server_default=text("current_timestamp(0)"), 
        onupdate=lambda: datetime.now(UTC)
    )

```

### SoftDeleteMixin

**`SoftDeleteMixin`** enables logical deletion without removing records. Lines 25-27 define a nullable `deleted_at` timestamp and an `is_deleted` boolean flag defaulted to `False`, allowing you to filter out deleted rows while preserving historical data.

```python

# From src/app/core/db/models.py

class SoftDeleteMixin:
    deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), default=None)
    is_deleted: Mapped[bool] = mapped_column(default=False, index=True)

```

## How to Apply Mixins to Your Models

Follow these steps to refactor existing models or create new ones using the provided mixins.

1. **Import the mixins** from the core module:

   ```python
   from ..core.db.models import UUIDMixin, TimestampMixin, SoftDeleteMixin
   ```

2. **Add the mixins to your class inheritance** after `Base`. The order does not affect SQLAlchemy behavior, but conventionally place `Base` first followed by the mixins.

3. **Remove duplicate column definitions** that the mixins now provide. Delete manual declarations of `uuid`, `created_at`, `updated_at`, `deleted_at`, and `is_deleted`.

4. **Retain model-specific columns** such as `name`, `email`, or foreign keys.

## Practical Refactoring Examples

### Refactoring the User Model

The original `User` model in [`src/app/models/user.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/models/user.py) (lines 12-30) manually declares all audit columns. Here is the refactored version using all three mixins:

```python

# src/app/models/user.py

import uuid as uuid_pkg
from datetime import UTC, datetime
from sqlalchemy import DateTime, ForeignKey, String
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column

from ..core.db.database import Base
from ..core.db.models import UUIDMixin, TimestampMixin, SoftDeleteMixin


class User(Base, UUIDMixin, TimestampMixin, SoftDeleteMixin):
    __tablename__ = "user"

    # Keep the integer primary key if your application requires it alongside UUID

    id: Mapped[int] = mapped_column(autoincrement=True, primary_key=True, init=False)
    
    name: Mapped[str] = mapped_column(String(30))
    username: Mapped[str] = mapped_column(String(20), unique=True, index=True)
    email: Mapped[str] = mapped_column(String(50), unique=True, index=True)
    hashed_password: Mapped[str] = mapped_column(String)
    
    profile_image_url: Mapped[str] = mapped_column(
        String, default="https://profileimageurl.com"
    )
    tier_id: Mapped[int | None] = mapped_column(
        ForeignKey("tier.id"), index=True, default=None, init=False
    )

```

### Refactoring the Tier Model

For the `Tier` model in [`src/app/models/tier.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/models/tier.py) (lines 9-16), which only requires timestamp tracking, import only `TimestampMixin`:

```python

# src/app/models/tier.py

from datetime import UTC, datetime
from sqlalchemy import String
from sqlalchemy.orm import Mapped, mapped_column

from ..core.db.database import Base
from ..core.db.models import TimestampMixin


class Tier(Base, TimestampMixin):
    __tablename__ = "tier"

    id: Mapped[int] = mapped_column(
        autoincrement=True,
        nullable=False,
        unique=True,
        primary_key=True,
        init=False,
    )
    name: Mapped[str] = mapped_column(String, nullable=False, unique=True)

```

## Benefits of Using SQLAlchemy Mixins

- **DRY Principle**: Column definitions exist in a single location. If you need to switch from `uuid7()` to `uuid4()` or adjust timezone handling, you change it once in [`src/app/core/db/models.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/db/models.py) rather than across every model file.
- **Schema Consistency**: Every model using `TimestampMixin` has identical column names and database defaults, simplifying query logic and migration scripts.
- **Soft-Delete Ready**: `SoftDeleteMixin` provides the infrastructure for logical deletion immediately. You can filter queries with `is_deleted=False` without altering the database schema later.

## Summary

- Import `UUIDMixin`, `TimestampMixin`, and `SoftDeleteMixin` from [`src/app/core/db/models.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/db/models.py) to add reusable columns to your SQLAlchemy models.
- Inherit these mixins alongside the declarative `Base` class defined in [`src/app/core/db/database.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/db/database.py).
- Remove redundant column definitions from your model classes after adding the mixins.
- The CRUD utilities in the boilerplate automatically recognize these mixin columns, requiring no changes to your data access layer.

## Frequently Asked Questions

### What order should I inherit the mixins in my model class?

You should place the declarative `Base` first, followed by the mixins in any order (e.g., `class User(Base, UUIDMixin, TimestampMixin, SoftDeleteMixin)`). SQLAlchemy's declarative system resolves column definitions from left to right, but since these mixins define non-overlapping columns, the inheritance order does not affect the final schema.

### Can I use only one mixin, or do I need to include all three?

You can import and use any combination of mixins independently. For example, reference models might only need `TimestampMixin`, while entity models might use all three. Simply import only the mixins your specific model requires from [`src/app/core/db/models.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/db/models.py).

### Do I need to update CRUD operations when using SoftDeleteMixin?

The existing CRUD utilities in [`src/app/crud/crud_users.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/crud/crud_users.py) and similar files automatically recognize the `is_deleted` and `deleted_at` columns. You can implement soft-delete filtering by adding `is_deleted=False` to your SQLAlchemy queries without modifying the CRUD base classes, as the columns are standard mapped attributes on the model.

### Where is the declarative Base defined that I must inherit alongside the mixins?

The declarative `Base` is defined in [`src/app/core/db/database.py`](https://github.com/benavlabs/fastapi-boilerplate/blob/main/src/app/core/db/database.py) at lines 10-14. All models in the benavlabs/fastapi-boilerplate must inherit from this `Base` class to ensure proper registry and metadata configuration, regardless of whether they use the provided mixins.