rent
Concepts

Database portability

The generated client is shared across Rent's supported SQL databases. The selected dialect changes SQL rendering, bind limits, identity handling, catalog inspection, migration operations, transaction options, and capability checks. Applications do not implement a separate repository for each vendor.

CapabilityPostgreSQLMySQLMariaDBSQLite
Typed CRUD and relationshipsYesYesYesYes
Transactions and savepointsYesYesYesYes
Optimistic lockingYesYesYesYes
Row lockingFull server formsServer formsServer formsNot supported; a lock clause fails validation
Insert returningComplete rowsGenerated ID plus reload when neededGenerated ID plus reload when neededComplete rows
Multiple schemasYesDatabase catalogsDatabase catalogsNot supported; @@schema is rejected
Structural alter migrationsNative operationsNative operationsNative operationsAtomic table rebuild when required
PostgreSQL extensions and RLSYesNoNoNo

Portable by default

Fields, relationships, predicates, typed projections, keyset cursors, eager loads, hooks, policies, encryption, external blobs, bulk writes, and transaction closures have one application-facing API. Rent's backend capability profile rejects an unsupported operation instead of silently changing its meaning.

The driver uses one closed database-pool abstraction internally because the supported backends are known at compile time. Backend-specific SQL binding and inspection stay behind that boundary; query and migration layers operate on shared AST and catalog types. This avoids duplicating high-level behavior while still allowing static dispatch in the hot path.

Database-specific behavior

Statement parameter budgets

Rent allows up to 65,535 bound parameters per statement on PostgreSQL, MySQL, and MariaDB, and 32,766 on bundled SQLite. An IN filter uses one parameter per value; compound keys use one per component. Filters, projections, and pagination values share that budget.

Generated bulk inserts and eager-loading key lists are batched automatically. Arbitrary queries are not split: doing so could change sorting, aggregate values, or a global limit. An oversized statement returns DriverError::ParameterLimit with the dialect, actual count, and maximum before execution. It does not include SQL or parameter values. A rejected statement leaves an open transaction usable.

For a large application-supplied membership filter, reduce the input set or express membership as a database subquery. Split independent writes inside a transaction when they must succeed or fail together. Custom database builds or connection-level restrictions can impose smaller limits, which are reported by the database itself.

The lower-level mutation planner also bounds insert and foreign-key attachment statements. Execute every statement in a transactional plan on the same transaction. Oversized PostgreSQL DO UPDATE plans and unconditional bidirectional updates require explicit smaller batches: automatic splitting could change how duplicate targets are handled. A planning error occurs before any statement is executed.

Native capabilities

Use explicit dialect features when the database offers something valuable that is not portable. PostgreSQL extensions, row-level security, domains, operator classes, and preload requirements are first-class catalog or extension concepts. MySQL and MariaDB retain their server identity and catalog differences. SQLite migration plans model table rebuilds so rows, indexes, and foreign keys can be preserved atomically.

Raw SQL remains available for a database feature Rent has not modeled. Keep that code at a narrow boundary and add a live test for every database it claims to support.

Compile only the required driver using the database setup guide. Use rent migrate preflight to discover unsupported or risky migration work before deployment.

On this page