
One schema for data, tenancy, and permissions.
Rent is a schema-first Rust ORM and database toolkit. Model your data and describe who can access it with optional relationship permissions. Generate a statically typed async client, review SQL migrations, and use PostgreSQL extensions such as pgvector, PostGIS, pgmq, and TimescaleDB as typed Rust packages. PostgreSQL first, with MySQL, MariaDB, and SQLite on the same client.
Schema in, Rust out
Write the schema once. Rent generates the client.
Models, relationships, and even pgvector columns are declared in RSL, a declarative schema language that reads the way modern ORM schemas do. Run rent generate to get Rust models and methods that match your schema. When a field changes, the compiler helps you update the code that uses it. Generation replaces the complete client together.
model User {
id BigInt @id
name String
posts Post[]
@@map("users")
}
model Post {
id BigInt @id
title String
author_id BigInt
author User @relation(fields: [author_id], references: [id])
embedding pgvector.Vector?
@@map("posts")
}Typed queries, typed extensions
Every query is checked by the Rust compiler.
Create records, load their relationships, page through a feed, or search by similarity with typed Rust builders. Setters collect values until you call save(). PostgreSQL and SQLite return inserted rows in the same statement. Use raw SQL for a specialized query.
let maya = client
.create_user_from(NewUser { name: "Maya".to_owned() })
.save()
.await?;
let posts = client
.post()
.title_contains("typed")
.with_author(|author| author)
.order_by(post::Post::id.desc())
.limit(20)
.all()
.await?;
let nearest = client
.post()
.nearest_cosine(post::Post::embedding, &query)
.limit(5)
.all()
.await?;Permissions in the schema
Share a post. Keep the rules in one place.
Maya owns a post. Ken can read or edit it when she shares it. Define those rules alongside the model, then use the ordinary generated client. Rent applies them for the signed-in person.
access {
subjects = [User]
}
permissions Post {
editor = author or [User]
viewer = editor or [User]
read = viewer
create = anyone
update = editor
delete, manage_grants = author
}let client = Client::connect(database_url).await?;
// Apply Maya's permissions to this client.
let maya = client.with_viewer(
Viewer::of(User::subject(maya_id)),
);
// Maya invites Ken to edit one post.
maya.post_permissions(&post_id)
.grant_editor(User::subject(ken_id))
.save()
.await?;Tenancy at the boundary
Bind the tenant once. Carry it through the request.
Acme and Northwind use the same tables. Bind the verified tenant once, and the generated client keeps reads, writes, and transactions inside that boundary. New rows receive the tenant automatically.
tenancy {
scope = "required"
field = "tenant_id"
}
model Post {
id BigInt @id
tenant_id BigInt
title String
}let client = Client::connect(database_url).await?;
// Bind the tenant from the verified request.
let acme = client
.with_viewer(verified_viewer.tenant(acme_id));
// The generated query stays inside Acme.
let posts = acme.post().all().await?;What you get
A complete data layer for Rust services
Relationship permissions alongside your models
Opt into shared access, inherited permissions, field grants, and delegated agents in RSL. Scoped clients enforce those rules through ordinary CRUD and transactions.
Built-in tenant isolation
Bind a tenant once. Scoped clients keep reads, writes, and relationships inside that customer's boundary, and reject a missing or conflicting scope. Custom application policies cannot remove it.
Transactions, locking, and retries
Closure transactions with savepoints, optimistic locking with version fields, row locks, isolation options, and retry policies for serialization failures.
Schema-first, one source of truth
Define models, relationships, indexes, permissions, and extensions in RSL. Organize one schema across as many files as you need, then generate the client and plan database changes from it.
PostgreSQL extensions as typed packages
pgvector, PostGIS, pgmq, pg_cron, pg_net, TimescaleDB, pg_search, pg_trgm, citext, pgcrypto, uuid-ossp, pg_jsonschema, pg_partman, and pgAudit, declared in the schema and preflighted before deploy.
Migrations you can review
Rent diffs the schema against the live database, classifies each change as safe, review, or destructive, writes append-only SQL, and seals it with checksums.
A generated, type-safe async client
Every model gets create, query, update, delete, and upsert builders with compile-time checked fields, predicates, eager loading, cursors, and streaming on Tokio.
Reuse fields and permission policies
Model mixins share fields and relationships. Permission profiles share access rules across resources, keeping large schemas concise without repeating each policy.
An editor that understands your schema
Cursor and VS Code support aligned formatting, jump to definition, and diagnostics for models, relationships, permission rules, profiles, and mixins.
One model, one flow
From schema to reviewed migration to running application.
Start with a model, generate its Rust API, and review the SQL that creates its tables. Rent checks the schema and compares it with the database so you can apply the changes your application needs.
rent new social-app --database postgres
cd social-app
rent migrate dev --name initial
cargo runComing from another ORM
How Rent compares
Coming from Prisma, Ent, SQLx, Diesel, or SeaORM? These pages show what changes and what stays, feature by feature.
Private preview
The docs are public. The source is by invitation.
Rent is in private preview while the first public release is prepared. Read what is available today, then ask for access or get in touch.
Start with SQLite, ship on PostgreSQL.
The getting-started guide takes four commands and no Docker. The tutorial grows the same schema through relationships, transactions, tenancy, migrations, and extensions.