# marshmallow-sqlalchemy: deriving marshmallow schemas from SQLAlchemy models

> marshmallow-sqlalchemy is the bridge between two libraries that each want to own the same model: SQLAlchemy describes the database shape, marshmallow handles serialization, and this library generates one from the other. You can declare fields by hand with auto_field or let the library derive them from the model with SQLAlchemyAutoSchema.

**marshmallow-code/marshmallow-sqlalchemy** — SQLAlchemy integration with marshmallow

- Repository: https://github.com/marshmallow-code/marshmallow-sqlalchemy
- Website: https://marshmallow-sqlalchemy.readthedocs.io
- Stars: 580 · Forks: 104
- Language: Python
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/marshmallow-code-marshmallow-sqlalchemy

## Two libraries that each want to describe the same object

marshmallow-sqlalchemy is the integration between the SQLAlchemy ORM and the marshmallow serialization library, and the project describes it plainly as a SQLAlchemy integration with the marshmallow (de)serialization library. The problem it solves is duplication. SQLAlchemy models describe columns, types, keys and relationships, and marshmallow schemas describe fields for input and output. Write both by hand and they drift, and the drift shows up as a serialization layer that quietly disagrees with the database. This library makes the schema derive from the model, or gives you per-field helpers so the schema is short enough to read and check by hand. The model stays the single source of truth, which is the point of the whole exercise.

## Declaring the models, and the schema that goes with them

The README's walkthrough declares an Author and a Book model, then writes the matching schemas by hand using the auto_field helper.

```python
    from marshmallow_sqlalchemy import SQLAlchemySchema, auto_field


    class AuthorSchema(SQLAlchemySchema):
        class Meta:
            model = Author
            load_instance = True  # Optional: deserialize to model instances

        id = auto_field()
        name = auto_field()
        books = auto_field()


    class BookSchema(SQLAlchemySchema):
        class Meta:
            model = Book
            load_instance = True

        id = auto_field()
        title = auto_field()
        author_id = auto_field()
```

The load_instance flag in the Meta class is the one that changes the behaviour most, because it makes the schema deserialize into model instances rather than plain dictionaries. The auto_field calls then do the per-column work, and the relationship field on the author schema is what pulls in the books.

## SQLAlchemyAutoSchema, and the two options that control derivation

You can also let the library generate the fields for a model's columns, using SQLAlchemyAutoSchema, and the README says the resulting classes are equivalent to the hand-written ones above.

```python
    from marshmallow_sqlalchemy import SQLAlchemyAutoSchema


    class AuthorSchema(SQLAlchemyAutoSchema):
        class Meta:
            model = Author
            include_relationships = True
            load_instance = True


    class BookSchema(SQLAlchemyAutoSchema):
        class Meta:
            model = Book
            include_fk = True
            load_instance = True
```

The two options decide how much the schema follows the model. include_relationships brings in the related objects rather than just their keys, which is convenient for nested output and expensive for large graphs. include_fk pulls in the foreign key columns, which is what you want when the client needs to reference the parent but should not receive the nested object. Neither is set by default, which is a sensible default given that one of them is usually wrong for a given API.

## Declare the models before the schemas, or the mappers run too soon

There is one ordering requirement that the README calls out explicitly. Make sure to declare Models before instantiating Schemas, otherwise sqlalchemy.orm.configure_mappers() will run too soon and fail. The reason is that the schema class body reads the model's mapper metadata, and the mapper configuration is what resolves relationships and column types. If the schema is imported before the models are defined, the mapper configuration runs against a half-defined model graph and raises. It is a simple rule, but it is the kind of thing that produces a confusing error the first time, because the traceback points into the ORM rather than into your import order. The same ordering discipline applies to the auto-generated schemas, since they inspect the model at class definition time.

## Dumping and loading, with the session passed in on load

The (de)serialization section shows the round trip.

```python
    author = Author(name="Chuck Paluhniuk")
    author_schema = AuthorSchema()
    book = Book(title="Fight Club", author=author)

    with Session() as session:
        session.add(author)
        session.add(book)
        session.commit()

        dump_data = author_schema.dump(author)
        print(dump_data)
        # {'id': 1, 'name': 'Chuck Paluhniuk', 'books': [1]}

    with Session() as session:
        load_data = author_schema.load(dump_data, session=session)
        print(load_data)
        # <Author(name='Chuck Paluhniuk')>
```

Two details are worth noting. The dumped books value is a list of identifiers rather than nested author objects, which is the include_relationships default in action, and the load call passes the session explicitly, so the deserialized Author is attached to it and can be committed. That session argument is the part people miss, since load returns a model instance and someone will assume it was persisted.

## Version floors, and a project moving to uv and flit

The packaging details in the project file tell you how actively it is maintained. The version is 1.6.0, the licence is MIT, and the dependencies are marshmallow 4.0.0 or newer and SQLAlchemy 1.4.40 or newer but below 3.0. The Python requirement is 3.10 or newer, with classifiers running from 3.10 through 3.14, and the maintainer is Steven Loria. The build backend is flit_core below 5, and the development tooling has moved to uv, with a uv.lock file at the root, a default dev group, and an exclude-newer setting of one week, which is a reproducible-build measure that pins dependency resolution to a week-old snapshot. The documentation groups are declared as dependency groups rather than extras, with docs, tests and lint groups, and tox with tox-uv for running the matrix. The tooling around the project is ruff for linting and formatting with a select of all checks minus an explicit ignore list, pre-commit for hooks, and renovate for dependency updates.

## Conclusion

marshmallow-sqlalchemy fits a Python API project that already uses SQLAlchemy for its models and marshmallow for its payloads, and that does not want to write a field list twice. It does not fit a team that wants a single library for both jobs, and it does not fit a codebase on marshmallow 3, since the current release requires marshmallow 4. Verify first that your SQLAlchemy version falls inside the supported range, since the dependency floor is 1.4.40 and the ceiling is below 3.0, and declare your models before instantiating your schemas, because the mapper configuration runs at import time and will fail if the order is wrong.

## FAQ

### What does marshmallow-sqlalchemy do?

It integrates the SQLAlchemy ORM with the marshmallow serialization library so you do not have to describe the same fields twice. You can generate fields automatically from a model's columns with SQLAlchemyAutoSchema, or declare them yourself with the auto_field helper on a SQLAlchemySchema subclass.

### Why do I get an error if I define a schema before my models?

The schema reads the model's mapper metadata, so sqlalchemy.orm.configure_mappers() runs too soon and fails. The README instructs you to declare the Models before instantiating the Schemas.

### What do include_relationships and include_fk do?

include_relationships brings related objects into the schema rather than just their keys, and include_fk includes the foreign key columns. The auto-generated equivalent of the hand-written schemas in the README uses include_relationships for the author and include_fk for the book.

### Which versions of SQLAlchemy and marshmallow are supported?

The package requires marshmallow 4.0.0 or newer and SQLAlchemy 1.4.40 or newer but below 3.0, and Python 3.10 or newer. The current version is 1.6.0 and the licence is MIT.

## Sources

- [Issues](https://github.com/marshmallow-code/marshmallow-sqlalchemy/issues)
- [License: MIT](https://github.com/marshmallow-code/marshmallow-sqlalchemy/blob/dev/LICENSE)
- [marshmallow-code/marshmallow-sqlalchemy on GitHub](https://github.com/marshmallow-code/marshmallow-sqlalchemy)
- [Project website](https://marshmallow-sqlalchemy.readthedocs.io)
- [README](https://github.com/marshmallow-code/marshmallow-sqlalchemy/blob/dev/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/marshmallow-code-marshmallow-sqlalchemy
