# How to Use FastCRUD Relationship Auto-Detection: A Complete Guide

> Master FastCRUD relationship auto-detection for seamless SQLAlchemy joins using auto_detect_relationships=True. Effortlessly include one-to-many relations with this guide.

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

---

**FastCRUD automatically joins SQLAlchemy relationships by passing `auto_detect_relationships=True` to methods like `get_joined` or `get_multi_joined`, with optional `include_one_to_many=True` for one-to-many relations.**

FastCRUD's relationship auto-detection eliminates manual join configuration when querying related data in FastAPI applications. This feature, implemented in the `benavlabs/fastcrud` repository, inspects your SQLAlchemy models for `relationship()` definitions and generates safe join conditions automatically. You can enable it on a per-query basis while retaining full control over nesting structure and relationship types.

## How Relationship Auto-Detection Works

The auto-detection system operates through three internal phases defined in [`fastcrud/core/field_management.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/core/field_management.py):

1. **Relationship Discovery** – The `discover_model_relationships` function inspects the SQLAlchemy mapper to identify all `relationship()` attributes on your model.

2. **Join Configuration** – For each discovered relationship, `build_relationship_joins_config` calls `auto_detect_join_condition` to generate safe join clauses. By default, it filters for **one-to-one** relationships only, unless you explicitly enable one-to-many support.

3. **Query Execution** – In [`fastcrud/crud/fast_crud.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/crud/fast_crud.py), methods like `get_joined` (around lines 1818-1843) replace manual join parameters with the auto-generated `JoinConfig` objects when `auto_detect_relationships` is truthy.

The `prepare_joins` function in [`fastcrud/core/query/joins.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/core/query/joins.py) then materializes these configurations into actual SQLAlchemy join clauses.

## Basic Usage with One-to-One Relationships

By default, FastCRUD only joins **one-to-one** relationships to prevent accidental Cartesian products. Instantiate your CRUD class and call `get_joined` with `auto_detect_relationships=True`:

```python
from fastcrud import FastCRUD
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import Depends, APIRouter

router = APIRouter()
user_crud = FastCRUD(User)

@router.get("/users/{user_id}")
async def read_user(user_id: int, db: AsyncSession = Depends(get_db)):
    return await user_crud.get_joined(
        db,
        schema_to_select=UserReadSchema,
        id=user_id,
        auto_detect_relationships=True,   # Auto-join all one-to-one relations

        nest_joins=True,                  # Return nested dicts instead of flat keys

    )

```

When `nest_joins=True`, the response structure places related data under nested dictionaries (e.g., `{"id": 1, "tier": {"name": "Premium"}}` rather than `{"id": 1, "tier_name": "Premium"}`).

## Including One-to-Many Relationships

To include **one-to-many** relationships (such as `User` → `Posts`), pass `include_one_to_many=True`. Be cautious with this option on large datasets, as it can create large result sets:

```python
@router.get("/users/{user_id}")
async def read_user_with_posts(user_id: int, db: AsyncSession = Depends(get_db)):
    return await user_crud.get_joined(
        db,
        schema_to_select=UserReadSchema,
        id=user_id,
        auto_detect_relationships=True,
        include_one_to_many=True,   # Enable one-to-many joins

        nest_joins=True,
    )

```

This configuration is documented in the method signature around lines 1582-1584 of [`fastcrud/crud/fast_crud.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/crud/fast_crud.py). The filtering logic resides in `build_relationship_joins_config` (lines 32-53 of [`fastcrud/core/field_management.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/core/field_management.py)).

## Selective Relationship Detection

Pass a list of relationship names to `auto_detect_relationships` to join specific relations while bypassing the default one-to-one filter:

```python
@router.get("/users/{user_id}")
async def read_user_selective(user_id: int, db: AsyncSession = Depends(get_db)):
    return await user_crud.get_joined(
        db,
        schema_to_select=UserReadSchema,
        id=user_id,
        auto_detect_relationships=["tier", "posts"],   # Explicit list of relation names

        nest_joins=True,
    )

```

When you provide a list, the logic in `build_relationship_joins_config` (lines 38-44) bypasses the `include_one_to_many` check and joins only the named relationships regardless of their cardinality.

## Multi-Record Queries with Auto-Detection

Use `get_multi_joined` to apply auto-detection to paginated lists. The method reuses the same internal flow as `get_joined` (see lines 1850-1880 in [`fastcrud/crud/fast_crud.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/crud/fast_crud.py)):

```python
@router.get("/users")
async def list_users(
    db: AsyncSession = Depends(get_db),
    limit: int = 10,
    offset: int = 0
):
    return await user_crud.get_multi_joined(
        db,
        schema_to_select=UserReadSchema,
        limit=limit,
        offset=offset,
        auto_detect_relationships=True,
        include_one_to_many=False,   # Keep to one-to-one for list views

        nest_joins=True,
    )

```

This returns a paginated response where each user record contains its nested one-to-one relations.

## Error Handling and Constraints

FastCRUD prevents ambiguous query construction by raising a clear error when you attempt to mix auto-detection with manual join parameters. The validation logic exists at lines 1828-1832 of [`fastcrud/crud/fast_crud.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/crud/fast_crud.py):

```python

# This raises ValueError

await user_crud.get_joined(
    db,
    schema_to_select=UserReadSchema,
    id=1,
    join_model=Tier,                     # Manual join parameter

    auto_detect_relationships=True,     # Conflicts with manual join

)

```

The error message states: *"Cannot use auto_detect_relationships with manual join parameters."* Use either the explicit `join_model`/`joins_config` approach **or** auto-detection, never both.

## Summary

- **Enable auto-detection** by passing `auto_detect_relationships=True` (or a list of relationship names) to `get_joined`, `get_multi_joined`, `get`, or `get_multi`.
- **Default behavior** only joins one-to-one relationships; set `include_one_to_many=True` to include collection-based relations.
- **Nest results** using `nest_joins=True` to receive hierarchical dictionaries instead of flat key hierarchies.
- **Conflict prevention** – Never combine `auto_detect_relationships` with explicit `join_model` or `joins_config` parameters.
- **Source implementation** resides in [`fastcrud/core/field_management.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/core/field_management.py) for relationship discovery and [`fastcrud/crud/fast_crud.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/crud/fast_crud.py) for query execution.

## Frequently Asked Questions

### What methods support the auto_detect_relationships parameter?

The `auto_detect_relationships` parameter is available in `get`, `get_multi`, `get_joined`, and `get_multi_joined` methods of the `FastCRUD` class defined in [`fastcrud/crud/fast_crud.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/crud/fast_crud.py). These methods delegate relationship discovery to `build_relationship_joins_config` in the field management module when the parameter is truthy.

### Why am I getting a ValueError when using auto_detect_relationships?

FastCRUD raises a `ValueError` if you mix `auto_detect_relationships` with explicit join parameters like `join_model`, `joins_config`, or `join_on`. This validation at lines 1828-1832 of [`fastcrud/crud/fast_crud.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/crud/fast_crud.py) prevents ambiguous query construction. Choose either automatic relationship detection or manual join configuration, not both.

### Does auto-detection work with many-to-many relationships?

Many-to-many relationships are treated as one-to-many from the perspective of the source side. They require `include_one_to_many=True` to be joined automatically. However, for complex many-to-many scenarios with association tables requiring specific join conditions, explicit `JoinConfig` objects remain the recommended approach according to the source implementation.

### How do I control the nesting structure of joined results?

Set `nest_joins=True` to receive nested dictionaries where one-to-one relationships appear as nested objects and one-to-many appear as lists. When `nest_joins=False` (the default), joined fields use prefixed keys (e.g., `tier_name`). The nesting logic is handled by `prepare_joins` in [`fastcrud/core/query/joins.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/core/query/joins.py), which processes the `JoinConfig` objects generated by the auto-detection system.