Build and deploy a Rust backend with Shuttle
Tags: rust, deployment, cloud
Published: 2023-01-11 11:21:00

---
title: Build and deploy a Rust backend with Shuttle
published: true
date: 2023-01-08 23:00:00 UTC
tags: rust, deployment, cloud
canonical_url: https://robertohuertas.com/2023/01/09/shuttle-rust-backend-deployment/
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c1ma40f3s8o4mz5drl9j.png
---

Learn how to build and deploy a Rust backend with [Shuttle](https://www.shuttle.rs/).

## Value proposition

What if I told you that you could **write a Rust backend and deploy it for free** in the cloud?

What if I told you that you could **get a Postgres database for free**, too?

What if I told you that you **wouldn’t have to worry about setting the whole infrastructure up**? Nor even have to deal with connection strings?

Finally, what if I told you that you could **use some of the most popular web frameworks available** in the Rust ecosystem?

To be honest, I couldn’t believe it myself when I first learnt about [Shuttle](https://www.shuttle.rs/), but I can say that they live up to their promise!

And on top of all that, their code is totally **open-source**!

## How to use it

Check out this [Axum’s](https://docs.rs/axum/latest/axum/) `Hello World` example:

```rust
use axum::{routing::get, Router};
use sync_wrapper::SyncWrapper;

#[shuttle_service::main]
async fn axum() -> shuttle_service::ShuttleAxum {
    let router = build_router();
    let sync_wrapper = SyncWrapper::new(router);
    Ok(sync_wrapper)
}

fn build_router() -> Router {
    Router::new().route("/", get(hello_world))
}

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

```

And now, let’s compare it to the code that you would write by not using [Shuttle](https://www.shuttle.rs/) at all:

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

#[tokio::main]
async fn main() {
    let router = build_router();
    axum::Server::bind(&"0.0.0.0:8000".parse().unwrap())
        .serve(router.into_make_service())
        .await
        .unwrap();
}

fn build_router() -> Router {
    Router::new().route("/", get(hello_world))
}

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

```

As you can see, both examples are **pretty similar**.

The only part of code that is different is the **entry point** of your app. The rest is the same. So, you could potentially **reuse the same code** to deploy it in your own infrastructure if you ever want to get away of [Shuttle](https://www.shuttle.rs/), thus avoiding the _vendor lock-in_.

## Adding a Postgres database

Adding a database is a piece of cake!

Forget about having to set up a user, dealing with connection strings and all that jazz. [Shuttle](https://www.shuttle.rs/) will inject a [sqlx pool](https://docs.rs/sqlx/latest/sqlx/type.PgPool.html) that you can use right away from your main function to work with your database.

But in order for this to happen, you will have to add a couple of dependencies to your `Cargo.toml` first:

```toml
shuttle-shared-db = { version = "0.8.0", features = ["postgres"] }
sqlx = { version = "0.6.2", features = ["runtime-tokio-native-tls","postgres"] }

```

Finally, go to your previous code and add a parameter to your entry point function (_note that it is annotated with a macro_):

```rust
#[shuttle_service::main]
async fn axum(#[shuttle_shared_db::Postgres] pool: PgPool) -> shuttle_service::ShuttleAxum {
  // ...
}

```

That’s it! You can now start working with [sqlx](https://github.com/launchbadge/sqlx) to deal with your new Postgres database.

> For the moment, [PostgreSQL](https://www.postgresql.org/) and [MongoDB](https://www.mongodb.com/) are the only supported databases.

### Initializing the database

Let’s say we want to create a simple table.

Create a file in the root of your project called `db/schema.sql` and add these lines to it:

```sql
CREATE TABLE IF NOT EXISTS test (
  id serial PRIMARY KEY,
  txt varchar(255) NOT NULL
);

```

Now, let’s add a few lines to the `axum` function:

```rust
#[shuttle_service::main]
async fn axum(#[shuttle_shared_db::Postgres] pool: PgPool) -> shuttle_service::ShuttleAxum {
    pool.execute(include_str!("../db/schema.sql"))
        .await
        .map_err(CustomError::new)?;
}

```

With that, every time our service starts, it will try to create the `test` table if it doesn’t already exist.

## The Shuttle CLI

But, wait a moment!

You may be wondering: “_What if I want to connect to my database with another client (i.e. [DBeaver](https://dbeaver.io/)) to inspect its contents or make a custom query?”.

Well, you can. I didn’t mention so far one of the **most important** [Shuttle](https://www.shuttle.rs/) parts: its **CLI**.

Basically, in order to run your code locally and deploy it to the cloud, you’ll need to use a CLI tool called [cargo-shuttle](https://crates.io/crates/cargo-shuttle).

In order to install it, just run:

```
cargo install cargo-shuttle

```

It has lots of [subcommands](https://docs.shuttle.rs/introduction/shuttle-commands) to help you **set up** a project from scratch and **manage** it.

Just by running `cargo shuttle init`, the CLI will guide you through a set of options that will let you choose, amongst other things, the name and location of your project, and the framework that you want to use.

[![cli](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/crvgy8iqwm94pn8kvskp.PNG)](https://robertohuertas.com/assets/images/shuttle-axum/v0.8.0-interactive-init.gif)

Just to name a few of the available frameworks:

- [actix-web](https://actix.rs/)
- [salvo](https://salvo.rs/)
- [axum](https://docs.rs/axum/latest/axum/)
- [poem](https://docs.rs/poem/latest/poem/)
- [tide](https://docs.rs/tide/0.16.0/tide/)
- [warp](https://docs.rs/warp/latest/warp/)
- [tower](https://docs.rs/tower/latest/tower/)

And no, I didn’t forget about the connection string :wink:. Whenever you `run` or `deploy` your project, if [cargo-shuttle](https://crates.io/crates/cargo-shuttle) detects you are using a database, it will let you know the connection string, so you can use it on your own.

![shuttle axum db](https://robertohuertas.com/assets/images/shuttle-axum/shuttle-axum-db.png)

## Infrastructure from Code

This is the way they have chosen to describe how they provision all the resources for you (databases, caches, subdomains, static folder…).

As you already saw, they’re using **annotations** in your code to understand if you are going to need a database or not, and just depending on that, they will provision that for you.

The idea is that you don’t need to define `infrastructure as code` but that **your code itself implicitly defines your infrastructure**. Pretty cool and impressive, IMHO!

## Many more things

There are many more things to discover.

Check out their amazing [set of examples](https://github.com/shuttle-hq/examples), which will get you up to speed in a blink of an eye.

On the other hand, I have prepared a [small GitHub repository](https://github.com/robertohuertasm/shuttle-axum) showcasing a **simple Axum Rest API** that uses a **Postgres database**.

This example is live, [here](https://shuttle-axum-2023.shuttleapp.rs/). Feel free to use [Postman](https://www.postman.com/) to play with it. You have the request file available [here](https://github.com/robertohuertasm/shuttle-axum/blob/master/reqs.http).

## Disclaimer

Note that I’m not in any way related to [Shuttle](https://www.shuttle.rs/) and this is not a “marketing” post of something like that.

I was so amazed when I discovered their service that I immediately felt the need to share my excitement with the rest of the world :wink:

In any case, bear in mind that **they’re in [public alpha](https://docs.shuttle.rs/community/contribute)** so the service is not really that stable, and they may change things or even disrupt the service at any time.

## Concluding thoughts

I think [Shuttle](https://www.shuttle.rs/) is a **great project** and it’s definitely **good news** for the Rust community.

It not only allows us to **deploy Rust backends easily for free** , but also **enables** lots of web developers coming from other languages to **approach the Rust web development ecosystem** and realize that **it’s not as intimidating** as one could think in the first place.

Let’s leverage this great opportunity to [get involved](https://docs.shuttle.rs/community/get-involved) and be part of this interesting project!

Cheers!