CLI tool
SeaQL/seaography avatar
SeaQL/seaography

Seaography: a GraphQL API generated from your SeaORM entities

🧭 A GraphQL framework for Rust

535 stars64 forksRustApache-2.0

At a glance

What is it?
Seaography bridges SeaORM and async-graphql so a database schema becomes a typed GraphQL API, with filters, pagination and nested relations derived from the entities, and a CLI that writes a ready-to-run server. It uses async-graphql's dynamic schema engine, trading static code generation for faster compile times.
Who is it for?
Seaography suits a Rust team that already uses SeaORM and wants a GraphQL layer without hand-writing resolvers for every entity, since the schema is derived from the entities and stays in sync with them, and the CLI produces a server you can run immediately.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 127 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem: a GraphQL layer per entity

Seaography describes itself as a powerful and extensible GraphQL framework for Rust that bridges SeaORM and async-graphql, turning your database schema into a fully-typed GraphQL API with minimal effort.

The problem it addresses is concrete. SeaORM is an async ORM for Rust with MySQL, PostgreSQL and SQLite support, and its entity definitions are the natural place to describe your domain. But a GraphQL API needs a schema, resolvers, and a decision about filters, pagination and relations for every entity. If you write those by hand you write them again for every new table, and they drift out of sync with the entities they describe.

Seaography's answer is to derive the GraphQL layer from the entities. The README lists what that gives you: a complete GraphQL schema directly from your SeaORM entities including filters, pagination and nested relations, derive macros to define custom input and output objects, queries and mutations mixed with SeaORM models, ready-to-run GraphQL servers generated by the included CLI, and RBAC, guards and lifecycle hooks for authorisation and custom business logic.

The stated goal is that you can focus on application logic instead of boilerplate. Whether that lands depends mostly on whether your API is a CRUD-shaped one over your database, which is the case this project optimises for.

The licence is MIT OR Apache-2.0, with both LICENSE-MIT and LICENSE-APACHE at the root, the homepage is sea-ql.org/Seaography, and the primary language is Rust.

Dynamic schema over code generation

The design decision that distinguishes Seaography from every other Rust GraphQL framework is the one in the second paragraph of the introduction. By leveraging async-graphql's dynamic schema engine, Seaography avoids the heavy code generation of static approaches, resulting in faster compile times.

That is a real trade-off and the README states it without hedging. The usual Rust GraphQL approach is a derive macro that expands into resolver code at compile time. The schema is then a compile-time artefact: if you break the schema, the build fails. The cost is that the macro expansion is heavy, and the compile time of a large schema is dominated by it.

Seaography instead builds the schema at runtime, by inspecting the SeaORM entity metadata and registering types with async-graphql dynamically. The Cargo.toml confirms the dependency choice, with async-graphql pulled in with default-features = false and the features dataloader and dynamic-schema enabled.

What you get in exchange is a schema that stays in sync with your entities by construction rather than by regeneration discipline, and a much faster build. What you give up is the compile-time guarantee. A malformed query is a runtime error rather than a build failure, and you lose the ability to catch schema mistakes in CI with a type check, which for some teams is the entire reason they chose Rust for their GraphQL server.

The generator/ and macros/ directories in the repository show that both approaches are present in some form, but the dynamic engine is the default path.

What the generated schema gives you

The features list is concrete and each item is a decision you would otherwise make per entity.

Rich types support covers the awkward scalars, with DateTime and Decimal called out as examples, and the Cargo.toml shows the optional feature flags that enable them, with with-chrono, with-time, with-uuid and with-decimal each pulling in the matching sea-orm and async-graphql support.

Relational query covers 1-to-1, 1-to-N and M-to-N, which is what makes the nested relation traversal work. Filtering uses operators such as gt, lt and eq, and you can filter by related entities, not just by columns on the entity itself. Order by any column is there. Pagination comes in two flavours, offset-based and cursor-based, and both are visible in the demo queries. Mutations cover create, update and delete. Guards and filters on an entity restrict access, which is the extension point for authorisation. And field names can be camel or snake case, with field-camel-case in the default feature set.

Two defaults in the Cargo.toml are worth noting. The default features are field-camel-case and schema-meta, and schema-meta in turn enables the macros plus serde derive and the Postgres array support, so the schema can describe its own type metadata.

The RBAC feature flag exists as well, rbac = ["sea-orm/rbac"], which means the authorisation story is delegated to SeaORM's own RBAC support rather than reimplemented.

Installing the CLIs and running the SQLite example

Two command line tools are needed, and the install step is two lines:

sh
cargo install sea-orm-cli@^2.0.0-rc # used to generate entities
cargo install seaography-cli@^2.0.0-rc

The first is SeaORM's own entity generator, and the --seaography flag in the usage below is what tells it to emit entities that Seaography understands.

The SQLite example is the quickest way to see the whole thing, and it needs no setup because sakila.db is shipped in the repository:

sh
cd examples/sqlite
sea-orm-cli generate entity -o src/entities -u sqlite://sakila.db --seaography
seaography-cli -o ./ -e src/entities -u sqlite://sakila.db seaography-sqlite-example
cargo run

The three steps are: generate the entities from the database, then run seaography-cli to generate the project around those entities, then run it. The output directory is set with -o and the entity directory with -e.

The MySQL and Postgres examples are the same three commands with a different connection string, and they need the sakila sample database set up first from the schema file in the example directory. The Postgres one uses sea-orm-cli generate entity -o src/entities -u postgres://user:pw@localhost/sakila --seaography followed by the matching seaography-cli invocation and cargo run.

The demo then serves on http://localhost:8000/.

Reading the generated query shape

The demo queries are worth reading because they show the shape of the generated API, which is where the design choices become visible.

Every entity query takes pagination, filters and orderBy arguments. The film query uses pagination with a page object carrying limit and page, orderBy with title: ASC, and then traverses into the actor relation, which returns its own nodes list, so a nested relation is a nested selection rather than a separate flat query.

Filters are nested objects keyed by field, with the operator as the inner key, so filters: { active: { eq: 0 } } and filters: { amount: { gt: "7" } }. The demo notes that amount is a Decimal and therefore a string in the filter, which is a small reminder that the filter values follow the column types.

Pagination comes in two shapes and returns different metadata. Page pagination returns paginationInfo with pages and current, while cursor pagination takes a cursor value like "Int[3]:271" and returns pageInfo with hasPreviousPage, hasNextPage and endCursor. The cursor form encodes the type, the length and the position, which is what makes it stable across insertions.

Relations can be filtered, ordered and paginated in their own right. The complex example traverses from customer into address and into payment, applies a filter on payment's amount, orders by amount, and pages within the relation, while also paging the outer customer list by cursor. That nested pagination is what makes the API usable for a client that renders lists inside lists.

Web frameworks, databases and the version matrix

Seaography is built on top of SeaORM, so the supported databases are MySQL, PostgreSQL and SQLite, plus SQL Server through SeaORM X. The Rust runtime is a minimum of 1.70 with edition 2021, and the workspace members are the root package, cli, generator and macros.

Web framework integration is described as easy with any framework, and the examples shipped out of the box cover Actix, Axum and Poem, one per database, alongside Loco examples in both the SeaORM and SeaORM Pro flavours. The pairing of one example per database and per framework is a nice touch for anyone deciding between them.

The version compatibility table is the part to read carefully, because Seaography tracks SeaORM's major line rather than having its own independent scheme. Seaography 2.0 pairs with SeaORM 2.0, and Seaography 1.1 pairs with SeaORM 1.1. The links in the table point at Seaography 2.0.0-rc and 1.1.4, and at SeaORM 2.0.0-rc and 1.1.13, so the pairing is exact rather than approximate. A project on SeaORM 1.1 should use Seaography 1.1, and mixing the two majors is not supported.

The release history is short and tells you where the project is. The newest tag is 2.0.0-rc.9 from 2026-06-18, before that 1.1.4 from 2025-02-14 and 1.1.3 from 2025-01-10. There is a CHANGELOG.md and a RELEASE.md at the root, and the last push to the repository was on 2026-06-18, the same day as the release candidate.

So the 2.0 line is a release candidate rather than a stable release, which matters for anyone planning to put this in front of users.

Where Seaography is the wrong choice

Three limits are structural. The first is the SeaORM dependency, and it is not a small one. Seaography is a GraphQL layer for SeaORM entities, so if your project uses sqlx, Diesel or the database directly, there is nothing here for you. Building your ORM around SeaORM to use Seaography is a much bigger decision than adopting a GraphQL library.

The second is the dynamic schema trade-off, seen from the other side. Avoiding code generation means faster compiles, but it also means the schema is not a compile-time artefact. You lose the guarantee that a schema error is a build failure, and if your team relies on a type-checked schema in CI as a safety net, you will have to replace that net with something else. The generated resolvers are also generic, so a query that needs real business logic will not be served by the generated path and you have to write a custom resolver, at which point you are maintaining both worlds.

The third is that the 2.0 line is still a release candidate, and the compatibility table is narrow. Seaography 2.0 pairs with SeaORM 2.0, which is itself a release candidate in the pinned dependency, sea-orm ~2.0.0-rc.40. Adopting a release candidate stack means the upgrade path is untested in production for anyone else, and the dependency floor of SeaORM 2.0.0-rc.40 means you cannot easily pin back to a stable SeaORM without pinning back Seaography to 1.1.

The alternative is a static GraphQL framework in Rust with derive macros and compile-time schema generation, where the schema is checked by the compiler and resolvers are yours to write. The difference in approach is exactly the one Seaography's introduction describes: static frameworks generate resolvers at build time and pay compile time for it, Seaography builds the schema at runtime from entity metadata and pays flexibility instead. For a CRUD-shaped API over a database, that trade is usually worth it. For an API with heavy custom logic on most endpoints, you will write most of the resolvers yourself and the dynamic schema buys you less than it costs.

Editorial conclusion

Seaography suits a Rust team that already uses SeaORM and wants a GraphQL layer without hand-writing resolvers for every entity, since the schema is derived from the entities and stays in sync with them, and the CLI produces a server you can run immediately. It is the wrong tool if you want a statically typed schema baked into your build, because the dynamic schema engine trades compile-time guarantees for compile speed, and it is the wrong tool if you are not using SeaORM, since that is the foundation of the whole thing. Verify first which SeaORM major line you are on, because the compatibility table pairs Seaography 2.0 with SeaORM 2.0 and Seaography 1.1 with SeaORM 1.1, and note that the newest release is 2.0.0-rc.9 from 2026-06-18 with the last push on the same day.

Frequently asked questions

What is Seaography and what does it build on?

It is a GraphQL framework for Rust that bridges SeaORM and async-graphql, turning your database schema into a fully-typed GraphQL API. The generated schema stays in sync with your SeaORM entities, and it uses async-graphql's dynamic schema engine rather than heavy code generation.

Which databases and web frameworks does Seaography support?

Because it is built on SeaORM it supports MySQL, PostgreSQL and SQLite, plus SQL Server through SeaORM X. Out-of-the-box examples exist for Actix, Axum and Poem, plus Loco in both the SeaORM and SeaORM Pro flavours.

How do I install Seaography and generate a project?

Run cargo install sea-orm-cli@^2.0.0-rc and cargo install seaography-cli@^2.0.0-rc, then generate entities with the --seaography flag and run seaography-cli with the -o output and -e entity directory options. The SQLite example ships sakila.db so you can simply do cargo run in examples/sqlite.

Which SeaORM version does my Seaography version need?

The compatibility table pairs Seaography 2.0 with SeaORM 2.0 and Seaography 1.1 with SeaORM 1.1, so the majors must match. The pins are exact: Seaography 2.0.0-rc and 1.1.4 against SeaORM 2.0.0-rc and 1.1.13.

What can the generated GraphQL schema do?

Rich types such as DateTime and Decimal, relational queries across 1-to-1, 1-to-N and M-to-N, filtering with operators like gt, lt and eq including filters on related entities, ordering by any column, offset and cursor pagination, create, update and delete mutations, guards and filters to restrict access, and a choice of camel or snake case field names.

How does Seaography handle authorisation?

Guards and filters on an entity restrict access and lifecycle hooks carry custom resolver logic, and there is an rbac feature flag that enables sea-orm/rbac. The README also lists RBAC, guards and lifecycle hooks as a first-class capability for implementing authorisation.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. SeaQL/seaography on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/seaql-seaography.svg)](https://hysenlabs.com/projects/seaql-seaography)

Was this useful?