Rust and PostgreSQL: Writing Performant Queries Without Pain

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Rust and PostgreSQL: A Duet That Makes Your Code Faster

\n\n

Have you ever wondered why more and more backend developers are switching to Rust? The answer is simple: Rust gives you control over memory and speed, while PostgreSQL gives you control over data. Together, they form a combination capable of handling hundreds of thousands of requests per second without slowdowns or memory leaks.

\n\n

In this guide, we'll break down how to make Rust and PostgreSQL work together. You'll learn how to set up a connection, execute queries, avoid SQL injections, and build asynchronous applications. Let's go!

\n\n

Why Rust and PostgreSQL?

\n\n

Rust is not just a trendy language. Its ownership system and borrow checker guarantee that you won't get a null pointer or dangling references. And PostgreSQL is not just a database. It's a powerful tool with support for JSON, full-text search, and complex transactions.

\n\n

When you combine Rust and PostgreSQL, you get:

\n
    \n
  • Security — Rust won't let you accidentally send incorrect SQL.
  • \n
  • Performance — asynchronous drivers operate at the C level.
  • \n
  • Control — you decide when and how to pull data.
  • \n
\n\n

Installation and Environment Setup

\n\n

Before writing code, make sure you have installed:

\n
    \n
  • Rust (latest stable version) — rustup update
  • \n
  • PostgreSQL (locally or via Docker) — docker run --name pg -e POSTGRES_PASSWORD=pass -p 5432:5432 -d postgres
  • \n
  • The libpq-dev library (for Linux) or its equivalent on Mac/Windows
  • \n
\n\n

Create a new project:

\n\n
cargo new rust-postgres-guide\ncd rust-postgres-guide
\n\n

Choosing a Driver: tokio-postgres vs sqlx

\n\n

There are two main approaches to working with PostgreSQL in Rust:

\n
    \n
  • tokio-postgres — a low-level asynchronous driver. Gives full control.
  • \n
  • sqlx — a high-level asynchronous driver with compile-time query checking.
  • \n
\n\n

For advanced projects, I recommend sqlx — it's more convenient and safer. But for maximum control, use tokio-postgres.

\n\n

Let's add dependencies to Cargo.toml:

\n\n
[dependencies]\ntokio = { version = "1", features = ["full"] }\nsqlx = { version = "0.7", features = ["runtime-tokio-rustls", "postgres"] }\nserde = { version = "1", features = ["derive"] }\n
\n\n

First Connection: Rust and PostgreSQL Meet

\n\n

Let's write a simple example that connects to the database and returns the PostgreSQL version.

\n\n
use sqlx::postgres::PgPoolOptions;\nuse std::error::Error;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn Error>> {\n    // Connection string: postgres://user:password@host:port/db\n    let database_url = "postgres://postgres:pass@localhost:5432/postgres";\n    \n    // Create a connection pool (reusable connections)\n    let pool = PgPoolOptions::new()\n        .max_connections(5)\n        .connect(database_url)\n        .await?;\n\n    // Execute the query\n    let row: (String,) = sqlx::query_as("SELECT version()")\n        .fetch_one(&pool)\n        .await?;\n\n    println!("PostgreSQL version: {}", row.0);\n    Ok(())\n}
\n\n

Run the code: cargo run. If everything is set up correctly, you'll see the PostgreSQL version. Note the PgPoolOptions — a connection pool is mandatory for production. It reuses connections and doesn't create new ones for each request.

\n\n

Creating Tables and CRUD Operations

\n\n

Now let's create a users table and perform basic operations: insert, read, update, delete.

\n\n

Migration: Creating a Table

\n\n

In sqlx, migrations are separate SQL files. Create a migrations folder and a file named

Blogs

Book Recommendations