rent
Getting started

Define a schema

Rent projects keep their data model in rent/schema.rsl. RSL follows familiar declarative model syntax wherever the concepts match, then uses the rent namespace for Rent-specific behavior:

datasource db {
  provider = "postgresql"
}

model User {
  id      BigInt @id @default(autoincrement())
  email   String @unique @db.VarChar(320) @rent.sensitive
  version UInt   @rent.version
  posts   Post[]

  @@map("users")
}

model Post {
  id       BigInt @id @default(autoincrement())
  authorId BigInt @map("author_id")
  author   User   @relation(fields: [authorId], references: [id], onDelete: Cascade)
  title    String

  @@index([authorId])
  @@map("posts")
}

User, User?, and User[] express required to-one, optional to-one, and to-many relationships. Rent resolves both sides of a relationship, synthesizes a correctly typed foreign key for compact declarations, and chooses stable join storage for implicit many-to-many relationships.

Run these commands while editing:

rent validate
rent format
rent describe
rent generate
rent migrate preflight

rent generate lowers RSL into Rent's versioned schema IR and generates Rust models, query builders, mutations, relation loaders, and the typed client. Application code imports generated Rust; it does not duplicate the data model as authored structs.

For a larger codebase, set schema in rent.toml to a directory. Rent recursively merges .rsl files in lexical path order and resolves relationships across file boundaries.

Rent-specific database objects remain beside the model they affect:

view ActiveUser {
  id    BigInt
  email String

  @@rent.sql("""
SELECT id, email FROM users WHERE active
""")
}

extension vector {
  name    = "vector"
  version = "0.8.1"
  schema  = "extensions"
}

Triple-quoted strings are an RSL extension intended for readable SQL. Dotted native attributes such as @db.Uuid remain valid, while differentiated features use @rent.version, @rent.generated, @rent.join, @@rent.check, @@rent.policy, and @@rent.rowLevelSecurity. Database connection URLs remain in Rent's project configuration and environment rather than the RSL datasource block, keeping the data model separate from runtime configuration.

Native PostgreSQL enums

Enums normally use portable text storage with generated Rust variants. Opt into a managed PostgreSQL enum when you also want the database to enforce its labels and comparison order:

enum PostState {
  DRAFT @map("draft")
  REVIEW @map("review")
  PUBLISHED @map("published")

  @@rent.native
  @@map("post_state")
  @@schema("publishing")
}

model Post {
  id BigInt @id
  state PostState @default(DRAFT)
}

The model requires PostgreSQL. Rent creates the namespace and type before its table, binds enum values with the correct SQL type, and inspects ordered labels for drift. PostState? permits SQL NULL. PostState[] remains a typed JSON collection rather than a native SQL array. Keep ordinary scalar fields as model identities. A unique native enum field can be the referenced key of a relationship; eager loading, traversal, connect helpers, upserts, and tenant policies treat it like any other key.

Adding labels is supported without rewriting existing rows. Put enum additions in their own migration and apply it before a migration that uses the new label in a default or data change. PostgreSQL requires that commit boundary. Removing or reordering existing labels requires a reviewed data migration; Rent does not silently replace the type or discard stored values.

On this page