Oct 23, 20265 min read

How to Deploy a Rust Backend to AWS with an AI Coding Agent

What Claude Code or Cursor has to write to get an Axum service with Postgres and Pub/Sub onto AWS, and how Encore lets the agent test the whole thing locally and deploy it to your own account.

Rust is a good language for an agent to write backend code in, because the compiler, through rules such as ownership, rejects whole classes of mistakes before anything runs, although that advantage stops at the edge of the binary.

When you ask an agent to deploy an Axum service with a database and a queue to AWS, the compiler has no opinion about the ECS task definition or the RDS security group, and those are the parts most likely to be wrong. In the IaC-Eval benchmark published at NeurIPS 2024, the best model tested passed under 20 percent of infrastructure-as-code tasks on the first attempt.

This guide compares the route where the agent writes that infrastructure with one where it only writes Rust.

Deploying Axum to AWS with an agent at a glance

StepWith EncoreECS and friends by hand
Axum codeSame Router, plus static resource declarationsSame Router, plus clients configured from the environment
PostgresDatabase::new in code, encore run starts Postgres locallyRDS instance and a local Postgres the agent sets up
Pub/SubTopic and Subscription staticsSNS topic, SQS queue, policies and a consumer loop
ContainerBuilt and deployed by EncoreDockerfile and ECR push the agent maintains
What the agent can test locallyThe whole service with its database and topicThe Rust code, with infrastructure checked on deploy

ECS and RDS by hand

The usual AWS layout for a Rust API is a container on ECS with Fargate behind an Application Load Balancer, with Postgres on RDS and SNS feeding SQS for events. The agent adds the AWS SDK for Rust and a Postgres client to the crate, configured from environment variables. It also writes a multi-stage Dockerfile that builds the release binary. Then it writes the infrastructure: the VPC and subnets, the ECS service with its task definition and roles, the RDS instance with its password in Secrets Manager, and the topic and queue with a queue policy and a consumer.

This gives the team complete control and works with any AWS service, and for an agent the cost is the feedback loop. A release build plus an image push plus an infrastructure apply takes minutes per attempt, and a wrong security group rule shows up as a timeout, which is a hard error for a model to reason about.

Encore: an infrastructure SDK for the Axum app

Encore

Encore combines an infrastructure SDK for your existing Rust code with a platform that provisions what that code declares, locally and in your own AWS account. The Axum app keeps its router. Resources are static declarations that Encore finds through static analysis, and the subscription is registered with an attribute:

use axum::{extract::Path, http::StatusCode, routing::post, Router}; use encore::pubsub::{Message, Subscription, Topic}; use encore::storage::postgres::Database; use serde::{Deserialize, Serialize}; // Postgres under `encore run`, RDS in your AWS account on deploy. static DB: Database = Database::new("users").migrations("./migrations"); #[derive(Debug, Clone, Serialize, Deserialize)] struct UserAdded { name: String, } // SNS and SQS in AWS, a local broker under `encore run`. static USER_ADDED: Topic<UserAdded> = Topic::new("user-added"); #[encore::pubsub::register] static WELCOME: Subscription<UserAdded> = Subscription::new(&USER_ADDED, "welcome", welcome); async fn welcome(msg: Message<UserAdded>) -> Result<(), encore::Error> { tracing::info!(name = %msg.data.name, "sending welcome email"); Ok(()) } async fn add_user(Path(name): Path<String>) -> StatusCode { if DB.execute("INSERT INTO users (name) VALUES ($1)", &[&name]).await.is_err() { return StatusCode::INTERNAL_SERVER_ERROR; } match USER_ADDED.publish(&UserAdded { name }).await { Ok(_) => StatusCode::CREATED, Err(_) => StatusCode::INTERNAL_SERVER_ERROR, } } #[tokio::main] async fn main() { encore::initialize(); let app = Router::new().route("/users/:name", post(add_user)); let addr = std::env::var("ENCORE_LISTEN_ADDR").unwrap_or("0.0.0.0:8080".into()); let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); axum::serve(listener, app) .with_graceful_shutdown(encore::shutdown::signal()) .await .unwrap(); std::process::exit(encore::shutdown::drained().await.code()); }

The route syntax is for Axum 0.7. An encore.service.json next to Cargo.toml names the service and exposes its HTTP routes:

{ "name": "axum_hello_world", "lang": "rust", "run": { "type": "rust" }, "api": [ { "type": "http", "prefix": "/", "name": "axum_hello_world", "expose": true } ] }

encore run starts Postgres locally, along with the topic, then runs the binary. The agent can curl -X POST localhost:4000/users/ada and query the users table while the welcome handler logs the event, all before a deploy. If something is wrong, the error is a Rust error or a SQL error on the agent's own machine, which it can fix in the same session.

On deploy, Encore provisions the database, topics and compute in your AWS account. The AWS infrastructure reference lists every resource, and connecting the account is done once by an admin through an IAM role. From then on the agent works in Rust, and cloud access sits with Encore's IAM role, not the agent.

Capacity and networking are configured per environment outside the code, which keeps an agent's change to a diff of the crate. Each pull request can also get a preview environment with its own infrastructure, so a reviewer can call the new route before merging.

Good to know

Encore covers the primitives most Rust backends need, including Postgres, Pub/Sub, object storage, cron, secrets and Redis. Crates that talk to other AWS services, such as DynamoDB, are used through the AWS SDK for Rust next to the Encore declarations.

Try Encore →

How to choose

  • Encore when you want the agent to write Rust and test against local Postgres and Pub/Sub, then deploy the same service to your own AWS account.
  • ECS and RDS by hand when the service has to fit an existing infrastructure repo and pipeline that a platform team runs.

Frequently asked questions

How do I deploy a Rust backend to AWS with an AI coding agent?

With Encore, the agent adds the encore-dev crate to the existing Axum app, declares the database and topics as statics and adds an encore.service.json. encore run starts Postgres locally along with a local Pub/Sub broker, so the agent can call the routes and check the result, and Encore provisions the database, topics and compute in your AWS account on deploy. Without Encore, the agent writes a Dockerfile and the ECS, RDS, SNS, SQS and IAM resources in infrastructure code, then deploys to test.

Does Encore replace Axum?

No. Routing, extractors and middleware stay in Axum. Encore is an infrastructure SDK, so the app keeps its Router and adds static declarations for the resources it uses.

Why is deploying Rust slow for an agent?

Release builds take time, and on top of that every infrastructure change is checked only against a real AWS account. Moving the checks to a local environment with real Postgres and Pub/Sub shortens the loop to a cargo build and a request.

Deploy to your cloud on AWS and Google Cloud
without managing infrastructure

Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.

~/orders — claude
Claude Code
Claude Code v2.1.180Opus 5.5~/orders