Minimalistic todo app with storage based on PostgreSQL DB with Diesel ORM - probably the first mature rust orm, currently used in and many other projects.

It has a number of advantages - stability, feature-completeness, plenty of configs and utility crates, and easy to use once you've set it up. High-performance and low-risk choice for lots of projects. However, the initial setup might be tricky because diesel crates link to host-provided db client libraries.

This example is using diesel-async because the rest of the server is async, and it's intended to showcase basic apis with a UI similar to other DB examples to easily compare their usage. To get started with this one you'll need:

  1. cargo install diesel_cli --no-default-features --features postgres - install diesel CLI that you'll need for common diesel-related ops
  2. docker run -p 5432:5432 -e POSTGRES_PASSWORD=password -d postgres - start a postgres instance in a docker container
  3. cd examples/databases/postgres-diesel && diesel setup --migration-dir="./migrations/" - setup database & migrations
  4. cargo run -p postgres-diesel - to start the example

It's powered by a few additional dependencies in the manifest:


name = "postgres-diesel"
edition = "2021"

name = "serve"
path = "./"

prest = "0.2"
serde = { version = "1", features = ["derive"] }
diesel = { version = "2.1.0", features = ["uuid"] }
diesel-async = { version = "0.3.1", features = ["deadpool", "postgres"] }

A separate manifest for the diesel configuration:


# For documentation on how to configure this file,
# see

file = "./"
custom_type_derives = ["diesel::query_builder::QueryId"]

dir = "./migrations"

A model that defines the auto-generated schema:

use diesel::{pg::Pg, prelude::*};
use prest::Uuid;

#[derive(Queryable, Selectable, Insertable, serde::Serialize, serde::Deserialize)]
#[diesel(table_name = crate::schema::todos)]
pub struct Todo {
    #[serde(default = "Uuid::new_v4")]
    pub uuid: Uuid,
    pub task: String,
    pub done: bool,

And a prest app that uses all of the above to manage todos:

pub mod models;
pub mod schema;

use prest::*;

use diesel::prelude::*;
use diesel_async::{
    pooled_connection::{deadpool::Pool, AsyncDieselConnectionManager},
    AsyncPgConnection, RunQueryDsl,
use models::Todo;
use schema::todos::dsl::*;

state!(DB_POOL: Pool<AsyncPgConnection> = {
    let database_url = "postgres://postgres:password@localhost/prest";
    let config = AsyncDieselConnectionManager::<AsyncPgConnection>::new(database_url);

fn main() {
        get(|| async { html!(@for todo in get_todos().await {(todo)}) })

async fn get_todos() -> Vec<Todo> {
    let mut con = DB_POOL.get().await.unwrap();
        .load(&mut con)
        .expect("successful select query")

async fn toggle_todo(Form(todo): Form<Todo>) -> Markup {
    let mut con = DB_POOL.get().await.unwrap();
        .get_result(&mut con)
        .expect("successful update query")

async fn add_todo(Form(todo): Form<Todo>) -> Markup {
    let mut con = DB_POOL.get().await.unwrap();
        .get_result(&mut con)
        .expect("successful insert query")

async fn delete_todo(Form(todo): Form<Todo>) {
    let mut con = DB_POOL.get().await.unwrap();
        .execute(&mut con)
        .expect("successful delete query");

impl Render for Todo {
    fn render(&self) -> Markup {
        html! {
            ."flex  items-center" hx-target="this" hx-swap="outerHTML" hx-vals=(json!(self)) {
                input."toggle toggle-primary" type="checkbox" hx-patch="/" checked[self.done] {}
                label."ml-4 text-lg" {(self.task)}
                button."btn btn-ghost ml-auto" hx-delete="/" {"Delete"}

async fn page(content: Markup) -> Markup {
    html! { html data-theme="dark" {
        (Head::with_title("With Diesel Postgres"))
        body."max-w-screen-sm mx-auto mt-12" {
            form."flex gap-4 justify-center" hx-put="/" hx-target="div" hx-swap="beforeend" hx-on--after-request="this.reset()" {
                input."input input-bordered input-primary" type="text" name="task" {}
                button."btn btn-outline btn-primary" type="submit" {"Add"}
            ."w-full" {(content)}