This plugin manages databases on Shuttle and connects them to your app. A shared database is in the same cluster as other user’s databases, but it is not accessible by other users.

If you want a high performing and isolated database, consider Shuttle AWS RDS.

You can connect to any type of remotely hosted database from your code, so do not let our current database offerings limit your creativity! Got other databases you want to see on Shuttle? Let us know!

Usage

Start by adding shuttle-shared-db to the dependencies for your service. Each type of shareable database is behind its own feature flag and macro attribute path.

EngineFeature flagAttribute path
Postgrespostgresshuttle_shared_db::Postgres
MongoDBmongodbshuttle_shared_db::MongoDb

Output type

By default, you can get the connection string to the database and connect to it with your preferred library. You can also specify other return types to get rid of common boilerplate.

Depending on which type declaration is used as the output type in the macro, you might need to activate additional feature flags:

EngineFeature flagType declarationDescription
PostgresStringThe connection string including username and password
Postgressqlx (with rustls) or sqlx-native-tlssqlx::PgPoolAn sqlx connection pool with reasonable defaults
MongoDBStringThe connection string including username and password
MongoDBmongodb::DatabaseA client pool connected to the database

Lastly, add a macro annotaion to the Shuttle main function. Here are examples for Postgres:

// Use the connection string
#[shuttle_runtime::main]
async fn main(#[shuttle_shared_db::Postgres] conn_str: String) -> ... { ... }

// With sqlx feature flag, get a PgPool connected automatically
#[shuttle_runtime::main]
async fn main(#[shuttle_shared_db::Postgres] pool: sqlx::PgPool) -> ... { ... }

Parameters

Both the Postgres and MongoDB macros take the same optional parameter:

ParameterTypeDescription
local_uri&strIf specified, on local runs, use this database instead of starting a Docker container for it

When passing in strings, you can also insert secrets from Secrets.toml using string interpolation. To insert the PASSWORD secret, pass it in like this:

#[shuttle_runtime::main]
async fn main(
    #[shuttle_shared_db::Postgres(
        local_uri = "postgres://postgres:{secrets.PASSWORD}@localhost:16695/postgres"
    )] conn_str: String,
) -> ... { ... }
Caveat: If you are interpolating a secret from Secrets.dev.toml, you need to set the same secret in Secrets.toml to a empty string so that this step does not crash in deployment.

The URI should be formatted according to the Postgres or MongoDB documentation, depending on which one you’re using.

If you do not specify a local_uri, then cargo-shuttle will attempt to spin up a Docker container and launch the database inside of it. For this to succeed, you must have Docker installed and you must also have started the Docker engine. If you have not used Docker before, the easiest way is to install the desktop app and then launch it in order to start the Docker engine.

Connection string

After deploying a project with a database macro, you can view the connection string with credentials with:

cargo shuttle resource list --show-secrets

Using the connection string, you can connect to it for manual querying, inspection, and migration. You can also export/import data using a dump tool suitable for the database of choice.

Example

The Shuttle poem main function below uses the #[shuttle_shared_db::Postgres] attribute macro to provision a shared Postgres database, which can be accessed using a pre-configured, authenticated sqlx Pool.

main.rs
#[shuttle_runtime::main]
async fn poem(
    #[shuttle_shared_db::Postgres] pool: PgPool,
) -> ShuttlePoem<impl poem::Endpoint> {
    pool.execute(include_str!("../schema.sql"))
        .await
        .map_err(CustomError::new)?;

    let app = Route::new()
        .at("/todo", post(add))
        .at("/todo/:id", get(retrieve))
        .with(AddData::new(pool));

    Ok(app.into())
}

The full example can be found on GitHub.