Skip to content

Prebuilt types

A prebuilt type is a type that Pavex expects you to build.
Whenever your mark a type as prebuilt, you're telling Pavex: "I'll build this type on my own, and then pass an instance over to you". In particular, you'll be passing that instance to ApplicationState::new, the constructor that Pavex generates for ApplicationState.

Defining a constructor

Use the #[prebuilt] attribute to define a new prebuilt type:

use pavex::prebuilt;

#[prebuilt]
pub struct DbConnectionPool {
    // [...]
}

Registration

Use an import to register in bulk all the prebuilt types defined in the current crate:

use pavex::{Blueprint, blueprint::from};

pub fn blueprint() -> Blueprint {
    let mut bp = Blueprint::new();
    bp.import(from![crate]); // (1)!
    // [...]
}
  1. You can also import prebuilt types from other crates or specific modules.

Alternatively, register prebuilt types one by one using Blueprint::prebuilt:

use crate::pool::DB_CONNECTION_POOL;
use pavex::Blueprint;

pub fn blueprint() -> Blueprint {
    let mut bp = Blueprint::new();
    bp.prebuilt(DB_CONNECTION_POOL); // (1)!
    // [...]
}
  1. DB_CONNECTION_POOL is a strongly-typed constant generated by the #[prebuilt] attribute on the DbConnectionPool type.
    Check out the documentation on component ids for more details.

The signature changes

Whenever you mark a type as prebuilt, the signature of the code-generated ApplicationState::new method will change to include that type as an input parameter.
In the generated server SDK for the example in the previous section, the signature of ApplicationState::new will change to:

// [...]
impl ApplicationState {
    pub async fn new(
        _app_config: crate::ApplicationConfig,
        v0: di_prebuilt::pool::DbConnectionPool,
    ) -> Result<crate::ApplicationState, crate::ApplicationStateError> {

Since the signature of ApplicationState::new changes, the calling code in your server crate will have to change accordingly. This may be surprising at first, since you don't often touch the code inside the server crate, but it's entirely expected. Don't worry: you just have to follow the compiler's suggestions to get back on track.

Immutability

The only crate you're never supposed to modify is the server SDK crate, the one that Pavex generates for you. The server crate, on the other hand, is yours to modify as you see fit.

Lifecycle

If a prebuilt input is only needed to construct singletons, it'll be discarded after ApplicationState::new returns.

If it's needed to process requests (e.g. as an input for a middleware), it'll be added as a field to ApplicationState. In this case, Pavex will treat it as a singleton and require it to implement the Send and Sync traits.