rent

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")
}

Explore schema

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?;

Explore queries

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?;

Explore permissions

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?;

Explore tenancy

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 run

Coming 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.