Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/launchbadge/sqlx/llms.txt

Use this file to discover all available pages before exploring further.

SQLx’s derive macros eliminate most of the repetitive trait implementation code that comes with a custom type system. With a single attribute you can generate row-to-struct mapping, SQL type declarations, parameter encoding, and column decoding — all from the shape of your Rust types. This page covers each macro and the attributes that control the generated code.
All derive macros require the derive feature flag:
[dependencies]
sqlx = { version = "0.8", features = ["derive"] }
The macros feature (for query! / query_as!) implies derive, so you only need to add it explicitly if you are not using the query macros.

#[derive(FromRow)]

FromRow maps a database row to a Rust struct. It is required by sqlx::query_as and sqlx::query_as! to deserialise query results.
use sqlx::FromRow;

#[derive(FromRow)]
struct User {
    id: i32,
    name: String,
    email: String,
}

let user = sqlx::query_as::<_, User>("SELECT id, name, email FROM users WHERE id = $1")
    .bind(1_i32)
    .fetch_one(&pool)
    .await?;
The generated implementation calls Row::try_get for each field using the field’s name as the column name. All field types must implement Decode and Type for the target database.

Field attributes

Maps a struct field to a differently-named column.
#[derive(FromRow)]
struct User {
    id: i32,
    name: String,
    #[sqlx(rename = "description")]
    about_me: String,
}
SELECT id, name, description FROM users;
--                ^^^^^^^^^^ read into `about_me`
Applied at the struct level, converts all field names to the given case before matching against column names. Useful when your database uses a different naming convention than your Rust code.
#[derive(FromRow)]
#[sqlx(rename_all = "camelCase")]
struct UserPost {
    id: i32,
    user_id: i32,    // mapped to "userId"
    contents: String, // mapped to "contents"
}
Supported values: snake_case, lowercase, UPPERCASE, camelCase, PascalCase, SCREAMING_SNAKE_CASE, kebab-case.
Numbers are not treated as word boundaries. foo1 in snake case stays foo1, not foo_1.
When a column is missing from the query result, uses Default::default() for the field value instead of returning an error.
#[derive(FromRow)]
struct User {
    id: i32,
    name: String,
    #[sqlx(default)]
    location: Option<String>, // None if the column is absent
}
You can also place #[sqlx(default)] at the struct level when the struct itself implements Default. Any column absent from the result is taken from the struct’s Default implementation:
#[derive(Default, FromRow)]
#[sqlx(default)]
struct Options {
    option_a: Option<i32>,
    option_b: Option<String>,
    option_c: Option<bool>,
}
Tells SQLx to call the field type’s own FromRow implementation instead of calling try_get directly. Use this to embed one struct inside another when the columns all come from the same flat row.
#[derive(FromRow)]
struct Address {
    country: String,
    city: String,
    road: String,
}

#[derive(FromRow)]
struct User {
    id: i32,
    name: String,
    #[sqlx(flatten)]
    address: Address,
}
SELECT id, name, country, city, road FROM users;
flatten is compatible with default.
Always populates the field from Default::default(), ignoring any column with the same name. Useful for fields that cannot or should not be decoded from SQL (for example, fields that hold non-SQL state like a Vec of related records).
#[derive(FromRow)]
struct User {
    name: String,
    #[sqlx(skip)]
    addresses: Vec<String>, // always an empty Vec
}
Decodes the column as type T and then converts to the field’s type using TryFrom. Handy when the database type differs from the Rust type you want to store.
#[derive(FromRow)]
struct User {
    id: i32,
    name: String,
    #[sqlx(try_from = "i64")]
    count: u64, // decoded as i64, then TryFrom<i64> converts to u64
}
Decodes a JSON or JSONB column and deserialises it using serde::Deserialize. Requires the json feature.
use serde::Deserialize;

#[derive(Deserialize)]
struct Metadata {
    version: u32,
    tags: Vec<String>,
}

#[derive(FromRow)]
struct Post {
    id: i32,
    title: String,
    #[sqlx(json)]
    metadata: Metadata,
}
By default, the column must not be NULL. If the column is nullable and the JSON value itself is never null, use #[sqlx(json(nullable))]:
#[derive(FromRow)]
struct Post {
    id: i32,
    #[sqlx(json(nullable))]
    metadata: Option<Metadata>, // NULL row → None; non-NULL row → Some(Metadata)
}

Manual FromRow implementation

When the derive macro is not flexible enough, implement the trait yourself:
use sqlx::{FromRow, Row};
use sqlx::sqlite::SqliteRow;

struct Foo {
    bar: MyCustomType,
}

impl FromRow<'_, SqliteRow> for Foo {
    fn from_row(row: &SqliteRow) -> sqlx::Result<Self> {
        Ok(Self {
            bar: MyCustomType {
                custom: row.try_get("custom")?,
            },
        })
    }
}

#[derive(Type)]

Type declares a SQL type for a Rust type, together with Encode and Decode implementations. It supports three modes: transparent newtypes, enumerations, and PostgreSQL composite types.

Transparent newtypes

#[sqlx(transparent)] makes a newtype delegate entirely to its inner field:
#[derive(sqlx::Type)]
#[sqlx(transparent)]
struct UserId(i64);
The generated Type impl reports the same SQL type as i64 (e.g. BIGINT). Encode and Decode forward to i64. Additional attributes for transparent types:
AttributeEffect
#[sqlx(type_name = "...")]Override the SQL type name instead of inferring it. PostgreSQL only.
#[sqlx(no_pg_array)]Skip generating PgHasArrayType. Required if the inner type does not implement PgHasArrayType (e.g. Vec<T>).
#[derive(sqlx::Type)]
#[sqlx(transparent, no_pg_array)]
struct UserIds(Vec<i64>); // Vec<i64> has no array type

Enum mapping

Enums can map to SQL integers or SQL strings depending on whether a #[repr(_)] attribute is present.
With #[repr(i32)] (or any integer repr), variants are stored and retrieved as their discriminant value:
#[derive(sqlx::Type)]
#[repr(i32)]
enum Color {
    Red = 1,
    Green = 2,
    Blue = 3,
}
The SQL type is the integer type matching the repr (e.g. INT for i32).

PostgreSQL composite types

A struct with named fields derives a composite type (PostgreSQL only). The type_name attribute sets the PostgreSQL type name:
#[derive(sqlx::Type)]
#[sqlx(type_name = "inventory_item")]
struct InventoryItem {
    name: String,
    quantity: i32,
    price: f64,
}
CREATE TYPE inventory_item AS (
    name TEXT,
    quantity INT,
    price DOUBLE PRECISION
);

#[derive(Encode)]

Encode alone is rarely needed; #[derive(Type)] generates it together with Decode. Use #[derive(Encode)] when you need parameter encoding but not decoding, or when you want encoding behaviour independent of Type.
#[derive(sqlx::Encode)]
struct Label(String);
For a transparent newtype this forwards encode_by_ref to the inner String. For structs and enums, the same rules as #[derive(Type)] apply.
If you are writing a type that only needs to be used as a query parameter (never read back from a row), #[derive(Encode)] together with a manual Type impl is the minimal setup required.

#[derive(Decode)]

Similarly, #[derive(Decode)] generates the Decode trait implementation on its own:
#[derive(sqlx::Decode)]
struct Label(String);
Use this when a type is only ever read from query results, not used as a bound parameter.

Summary

FromRow

Maps a database row to a struct. Required for query_as. Supports renaming, defaults, flattening, skipping, type conversion, and JSON fields.

Type

Declares a SQL type for a Rust type and generates Encode + Decode. Supports transparent newtypes, integer or string enums, and PostgreSQL composites.

Encode

Generates parameter binding only. Use when the type is write-only (query parameters) or when you need a custom Type with generated encoding.

Decode

Generates column decoding only. Use when the type is read-only (query results) or when you need a custom Type with generated decoding.

Build docs developers (and LLMs) love