Skip to content
Postgres extensions

pg_partman

What it is

pg_partman manages PostgreSQL declarative partitions. It creates future partitions, applies retention rules, and maintains time- or number-based partition sets as data grows.

What it provides

  • Automated creation and maintenance of child partitions
  • Time-based and numeric partition intervals
  • Retention policies and migration helpers for existing tables
  • An optional background worker for scheduled maintenance

Use it for event logs, audit tables, large append-only histories, time-bounded business records, or any table where predictable partition creation and retirement should be automated.

Use it with Rent

extension pg_partman {
  name = "pg_partman"
  schema = "partman"
}

The RSL declaration makes installation and migration intent part of the reviewed application schema. Register the typed pack at runtime to call its APIs:

let partman = extensions.register_pack::<PgPartman>()?;
let events = partman
    .client(&pool)
    .partitioned_table("public.events");

events
    .create("created_at", "1 month")
    .await?;

partman
    .client(&pool)
    .run_maintenance()
    .await?;

Create the parent table with PostgreSQL's PARTITION BY RANGE clause before registering it with pg_partman. Calling run_maintenance directly does not require the optional pg_partman background worker. For automatic maintenance, configure that worker or schedule maintenance with pg_cron as an operational choice.

Run the application

Add the extension declaration above to your application's schema. Confirm that your PostgreSQL provider offers the extension and that your migration role can install it, then apply the migration and run your application:

rent migrate dev --name enable_pg_partman --schemas public,partman
cargo run

Complete example

Download this project, or copy the files below into an empty directory.

Replace RENT_REPOSITORY_URL in Cargo.toml with the URL supplied with your preview access. Use the matching Rent CLI release.

Use an empty PostgreSQL database with the extension binaries available on its server. Set DATABASE_URL to that database and follow any server setup requirements described above.

rent extension check --provider self-hosted
rent generate
rent migrate dev --name initial --schemas public,partman
cargo run

If your host preinstalls other extensions, declare those in RSL as well. For a database with existing application tables, baseline it first.

Cargo.toml
[package]
name = "rent-extension-pg-partman"
version = "0.1.0"
edition = "2024"
[workspace]
[[bin]]
name = "rent-extension-pg-partman"
path = "main.rs"
[dependencies]
rent = { git = "RENT_REPOSITORY_URL", tag = "v0.8.6", default-features = false, features = ["postgres", "extensions", "migrate"] }
rent-ext-pg-partman = { git = "RENT_REPOSITORY_URL", tag = "v0.8.6" }
anyhow = "1.0.104"
tokio = { version = "1.53.1", features = ["full"] }
rent.toml
schema = "schema.rsl"
generated = "generated"
migrations = "migrations"

[database]
dialect = "postgres"
backends = ["postgres"]
schema.rsl
datasource db {
  provider = "postgresql"
}

extension pg_partman {
  name   = "pg_partman"
  schema = "partman"
}

model Post {
  id    BigInt  @id
  title String
  body  String  @default("")
}
main.rs
use anyhow::Result;
use rent::{driver::DatabasePool, extension::ExtensionRegistry};
#[allow(dead_code, unused_imports)]
#[rustfmt::skip]
#[path = "generated/mod.rs"]
mod generated;
#[tokio::main]
async fn main() -> Result<()> {
    let pool = DatabasePool::connect_url(&std::env::var("DATABASE_URL")?).await?;
    let mut extensions = ExtensionRegistry::default();
    use rent_ext_pg_partman::{PgPartman, PgPartmanClientExt};
    let pack = extensions.register_pack::<PgPartman>()?;
    pool.execute("CREATE TABLE IF NOT EXISTS public.post_events (created_at timestamptz NOT NULL, title text NOT NULL) PARTITION BY RANGE (created_at)").await?;
    pack.client(&pool)
        .partitioned_table("public.post_events")
        .create("created_at", "1 month")
        .await?;
    pack.client(&pool).run_maintenance().await?;
    println!("Time partitions are ready for post events.");
    Ok(())
}