graphql-orm generates async-graphql query/mutation types, typed filters, ordering, pagination,
relation loading, repository helpers, schema metadata, and migration plans from Rust entity structs.
This repository also contains the independently consumable AI, backup, and storage companion crates. Applications depend only on the packages they need; workspace membership does not enable the companion crates as ORM features.
It is designed for two related use cases:
- greenfield SQLite/Postgres apps where Rust entity metadata can own the database schema
- existing databases, especially legacy Microsoft SQL Server schemas, where the ORM should provide a safe generated GraphQL read layer without taking ownership of writes or migrations
#[derive(GraphQLEntity)]for GraphQL object types, SQL row decoding, filters, order inputs, and schema metadata#[derive(GraphQLOperations)]for generated list queries, single-entity lookups, repository helpers, and write operations where the backend supports writes- generated resolver-operation descriptors and schema-root exposure catalogs with deterministic drift fingerprints
#[derive(GraphQLRelations)]for nested relation fields with batched loading- SQLite and PostgreSQL read/write support through SQLx
- Microsoft SQL Server read/query-only support through Tiberius
- validated runtime-schema filters, deterministic keyset reads, and owned records on SQLite/PostgreSQL without compiled entity types
- schema-bound, least-privilege runtime relation batching with composite keys, per-parent keysets, and optional counts
- single and composite primary-key read support
- single and composite relation-key batching, including nested legacy shapes like
JimCardFiles -> Contacts -> Details - portable spatial fields and predicates with native PostGIS support and SQLite GeoJSON fallback
- portable per-entity full-text search with native Postgres search tables and SQLite FTS5 support
- explicit schema ownership policies for managed, external, validate-only, and plan-only schemas
- ABI-style schema migration stages for managed SQLite/Postgres schemas
- row, field, and entity policy hooks for application-owned access control
- project-agnostic
AuthSubjectand exact-scopeScopeEntityPolicyhelpers - opt-in PostgreSQL row-level security metadata and request-local database auth context
- backend-neutral typed read projections that omit sensitive columns from SQL and process memory
- typed composite-key, insert-if-absent, conditional, and bounded mutation APIs
- federation-composable conventional GraphQL operation roots with stable Rust root names
- dependency-owned schema modules with stable migration, backup, and restore metadata
- owned backend-neutral runtime schema IR with validation, canonical fingerprints, and static-metadata conversion
- owned runtime values, fingerprint-bound schema handles, projections, and exact SQLite/PostgreSQL row decoding
- backend-neutral fenced lease transitions for durable workers
- bounded forward and backward repository keyset windows for large timelines
- opt-in policy-gated bounded retention purge for managed append-only entities
Select exactly the backend support your service needs:
[dependencies]
graphql-orm = { git = "https://github.com/Dastari/graphql-orm.git", rev = "<reviewed-full-40-character-commit-sha>", version = "0.16.0", default-features = false, features = ["sqlite"] }GitHub with an exact full revision is the only supported distribution method. The workspace packages are
not published to crates.io. Replace the placeholder with the reviewed release commit (the version tag
is an identity aid, not a substitute for rev). The optional auth-agql bridge likewise resolves
the exact upstream revision 3f3b0c5365adfbe436514a681d977b600991b797.
Available backend features:
sqlite- activates only SQLx SQLite supportpostgres- activates only SQLx PostgreSQL supportmssql- read/query-only SQL Server support without either SQLx database driver
Optional integration features:
auth-agql- optional one-way bridge fromagql-auth0.12 principals intoAuthSubject/DbAuthContext
Naming features are independent of backend features:
resolver-case-*argument-case-*field-case-*
When one backend feature is enabled, existing single-backend shorthand remains available. In
multi-service workspaces, Cargo may unify backend features; in that mode each entity and
schema_roots! block must declare an explicit backend.
use graphql_orm::prelude::*;
#[derive(GraphQLEntity, GraphQLOperations, Clone, Debug, serde::Serialize, serde::Deserialize)]
#[graphql_entity(table = "users", plural = "Users", default_sort = "name ASC")]
pub struct User {
#[primary_key]
pub id: String,
#[filterable(type = "string")]
#[sortable]
pub name: String,
#[filterable(type = "boolean")]
pub active: bool,
}
schema_roots! {
auth: "required",
query_custom_ops: [],
entities: [User],
}
async fn build_schema(database_url: &str) -> graphql_orm::Result<AppSchema> {
let database =
graphql_orm::db::Database::<graphql_orm::SqliteBackend>::connect_sqlite(database_url)
.await?;
Ok(schema_builder(database)
.data(AuthSubject::new("current-user-id"))
.finish())
}Generated resolver auth can be set at the schema root or entity level with
auth = "required" | "optional" | "none". The default preserves the previous fail-closed generated
auth behavior; use auth: "none" for public generated schemas.
Generated GraphQL includes list and single lookup queries:
query {
users(where: { active: { eq: true } }, orderBy: [{ name: ASC }]) {
edges {
node { id name active }
}
pageInfo { totalCount hasNextPage }
}
}SQLite/Postgres entities also get generated mutations and repository helpers unless policy/backend settings make them unavailable.
For persisted types that must never enter the GraphQL type registry, derive
RepositoryEntity with #[repository_entity(...)]. It generates ordinary Rust
filter/order/create/update/projection types and applicable typed repository and
transaction operations, but no async-graphql object, input, resolver,
connection, payload, subscription, or schema-root implementation. Private and
sensitive fields remain available to trusted repository inputs, with generated
debug output and mutation side effects redacted. The storage model and stable
schema hash are identical to an equivalent GraphQL-enabled declaration.
schema_roots! can hide generated GraphQL mutations without disabling generated repository
writes. generated_mutations defaults to "all" for compatibility; use "none" to expose only
custom mutation roots from extra_mutation_types, or use "allowlist" with
generated_mutation_allowlist: [Entity] / "denylist" with
generated_mutation_denylist: [Entity] for mixed public exposure.
GraphQLOperations also implements GraphqlOperationMetadata, while
schema_roots! emits graphql_orm_operation_catalog(). The catalog reports
the exact generated root field names, categories, argument/result signatures,
backend profile, and resolved generated-mutation exposure. Its fingerprints
detect generated-surface drift; they do not authorize execution or bind a
document projection or disclosure policy. See
generated resolver operation metadata.
SQL Server support is intentionally read-only. It lets projects point the same entity/filter/query system at existing databases without generating writes or migrations.
use graphql_orm::prelude::*;
#[derive(GraphQLEntity, GraphQLOperations, Clone, Debug, serde::Serialize, serde::Deserialize)]
#[graphql_entity(
backend = "mssql",
table = "dbo.Jobs",
plural = "Jobs",
schema_policy = "external_read_only",
default_sort = "[JobId] ASC"
)]
pub struct Job {
#[primary_key]
#[graphql_orm(db_column = "JobId", write = false)]
#[filterable(type = "number")]
#[sortable]
pub id: i32,
#[graphql_orm(db_column = "JobName", write = false)]
#[filterable(type = "string")]
#[sortable]
pub name: String,
}
schema_roots! {
backend: "mssql",
schema_policy: "external_read_only",
query_custom_ops: [],
entities: [Job],
}Create a SQL Server database handle from an ADO.NET-style connection string:
let database = graphql_orm::db::Database::<graphql_orm::MssqlBackend>::connect_ado(
"server=tcp:127.0.0.1,1433;\
database=LegacyDb;\
user id=sa;\
password=Your_strong_password123;\
TrustServerCertificate=true",
)
.await?
.with_schema_policy(graphql_orm::graphql::orm::SchemaPolicy::ExternalReadOnly);Composite relation keys use array syntax and batch efficiently across SQLite, Postgres, and MSSQL:
#[graphql(skip, name = "Details")]
#[relation(
target = "JimCardFileDetail",
from = ["card_no", "cont_no"],
to = ["CardNo", "ContNo"],
multiple,
emit_fk = false
)]
pub details: Vec<JimCardFileDetail>,A nested query such as JimCardFiles -> Contacts -> Details executes as one parent query plus one
batched relation query per relation layer, not N+1 or nested N*N queries.
- Getting started
- Backend features and multi-backend workspaces
- Entities, keys, columns, naming, and relations
- PostgreSQL RLS and auth-aware execution
- SQL Server read-only backend
- Schema ownership, validation, planning, and ABI migrations
- Writes, repository helpers, hooks, subscriptions, and policies
- Portable transactions, CAS, append-only entities, constraints, and keysets
- Binary keys, private repository upserts, and conditional indexes
- Typed least-privilege read projections
- Repository-only persisted entities
- Typed composite-key and bounded mutations
- Bounded append-only retention maintenance
- Backup runtime API
- Schema modules and fenced leases
- Monorepo consolidation and consumer migration
- Release notes
- Development and test commands
The crate is under active development. SQLite/Postgres write paths and schema management are available for managed schemas. SQL Server is currently read/query-only by design.
crates/graphql-orm- runtime crate used by applicationscrates/graphql-orm-macros- proc-macro crate re-exported bygraphql-ormcrates/graphql-orm-storage- provider-neutral object storage primitivescrates/graphql-orm-backup- backup and restore orchestrationcrates/graphql-orm-ai- project-agnostic AI agent runtime
Applications should depend on graphql-orm and use the re-exported macros from
graphql_orm::prelude::*.