The simplest way to build and deploy a web app on Shuttle looks like this:

use axum::{routing::get, Router};

async fn hello_world() -> &'static str {
    "Hello, world!"
}

#[shuttle_runtime::main]
async fn main() -> shuttle_axum::ShuttleAxum {
    let router = Router::new().route("/", get(hello_world));

    Ok(router.into())
}

This example spins up a server where the / endpoint returns Hello, world!. But most importantly, the code you see in the snippet above, is all it takes for cargo shuttle deploy to deploy it.

This is possible due to the #[shuttle_runtime::main] procedural macro. The macro wraps your app with Shuttle’s runtime. The Shuttle runtime receives commands from the deployers, such as load, start, and stop. The loading phase provisions resources for the app (see below).

Provisioning Resources

Shuttle macros

In the example above, the 2 annotations in the main function expand to code that makes the Shuttle runtime provision them on our end.

Here are the examples on how to use them, once you add the required annotations to your code:

Secrets

#[shuttle_runtime::main]
async fn axum(
    #[shuttle_secrets::Secrets] secret_store: SecretStore,
) -> shuttle_axum::ShuttleAxum {
    // Get secret defined in `Secrets.toml` file.
    let secret = if let Some(secret) = secret_store.get("MY_API_KEY") {
        secret
    } else {
        return Err(anyhow!("secret was not found").into());
    };
}

Postgres Database

#[shuttle_runtime::main]
async fn axum(
    #[shuttle_shared_db::Postgres] pool: PgPool,
) -> shuttle_axum::ShuttleAxum {
    // We can query our Postgres database with `pool`
    pool.execute(include_str!("../schema.sql"))
        .await
        .map_err(CustomError::new)?;
}

For more info on resources, head on over to our Resources section.

Deploying your Project

When you run cargo shuttle deploy, your project code is archived and sent to our servers where it is compiled. Our codegen in shuttle_runtime::main will embed a gRPC server in the binary that we will be used to start and stop your service, as well as a Loader struct that will provision the resources you request in the arguments to your main function. Your service will then be started on Shuttle’s infrastructure in the eu-west2 region of AWS.

More reading

Check out the files and environment sections for more details.


If you wish to contribute to Shuttle and learn more about how Shuttle works under the hood, check out our Contributing Guide.