# Encore.rs

> An infrastructure SDK for Rust

Encore.rs is an infrastructure SDK for Rust. You declare the infrastructure your application needs, such as databases, Pub/Sub topics, object storage buckets, Redis databases, cron jobs and secrets, as `static`s in your Rust code, and use them through their methods. Encore reads the declarations from your source, runs matching infrastructure locally with `encore run`, and provisions the real resources when you deploy.

The SDK is the `encore-dev` crate, imported as `encore`. It links Encore's Rust runtime directly: there is no FFI layer and no code generation.

Encore.rs covers infrastructure only. It has no API framework: you serve HTTP with the web framework you already use, such as [axum](https://github.com/tokio-rs/axum) or actix-web, and call the SDK from your handlers.

> **Note**
>
> Encore.rs is in early access. APIs may still change, and some features are not yet available. The sections below note where behavior is incomplete.

## What you get with Encore.rs

- **Infrastructure as Rust**: declare [databases](/docs/rs/primitives/databases), [Pub/Sub topics and subscriptions](/docs/rs/primitives/pubsub), [object storage buckets](/docs/rs/primitives/object-storage), [Redis databases](/docs/rs/primitives/redis), [cron jobs](/docs/rs/primitives/cron-jobs), [secrets](/docs/rs/primitives/secrets) and [configuration](/docs/rs/develop/config) as `static` values. Encore works out from your code which service uses what, and grants exactly that access.
- **Local infrastructure, automatically**: `encore run` starts Postgres, a Pub/Sub broker, an object storage emulator and a Redis server for your app, applies your migrations, and builds and runs each service with Cargo.
- **Isolated tests**: under `encore test`, every test gets its own databases, buckets, Redis databases and topics. See [Testing](/docs/rs/develop/testing).
- **Observability**: database, Pub/Sub, object storage and Redis calls are traced, and your own spans join them through OpenTelemetry. See [Tracing](/docs/rs/observability/tracing), [Logging](/docs/rs/observability/logging) and [Metrics](/docs/rs/observability/metrics).
- **Your own web framework**: Encore.rs doesn't own your `main` or your router.

## The infrastructure primitives

Each primitive is a module-level `static`, built with a `const` constructor. Options are chained onto the constructor.

**Database**

```rust
use encore::storage::postgres::Database;

static DB: Database = Database::new("orders").migrations("./migrations");
```

**Pub/Sub**

```rust
use encore::pubsub::Topic;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct OrderPlaced {
    order_id: String,
}

static ORDERS: Topic<OrderPlaced> = Topic::new("order-placed");
```

**Object Storage**

```rust
use encore::objects::Bucket;

static INVOICES: Bucket = Bucket::new("invoices");
```

**Redis**

```rust
use encore::storage::redis;

static SESSIONS: redis::Database = redis::Database::new("sessions");
```

**Cron Jobs**

```rust
use encore::cron::{Job, Schedule};

static SEND_INVOICES: Job =
    Job::new("send-invoices", "/internal/send-invoices", Schedule::Every("2h"))
        .title("Send pending invoices");
```

**Secrets**

```rust
use encore::secrets::Secret;

static STRIPE_KEY: Secret = Secret::new("StripeKey");
```

Encore reads these declarations statically, so a few rules apply to all of them:

- A declaration is a `static` at module level, not a local variable or a value built in a function.
- Names and options are string literals (or other literals) written at the declaration.
- A declared resource is used by calling its methods. To hand it to other code, create a handle, such as a `DatabaseRef` from `DB.read()`.
- Every use must be inside a [service](/docs/rs/primitives/services), so Encore knows which service to grant it to.

Encore reports a broken rule when it parses the app, on `encore run`, `encore test` or `encore build`, even where the Rust compiler accepts the code.

## Bring your own web framework

A Rust service is an ordinary binary. It listens on the address Encore gives it in the `ENCORE_LISTEN_ADDR` environment variable (`PORT` carries the same port), and calls the SDK from its handlers. With axum:

```rust
-- src/main.rs --
use axum::{extract::Path, http::StatusCode, routing::post, Router};
use encore::storage::postgres::Database;

static DB: Database = Database::new("users").migrations("./migrations");

async fn add_user(Path(name): Path<String>) -> StatusCode {
    match DB.execute("INSERT INTO users (name) VALUES ($1)", &[&name]).await {
        Ok(_) => StatusCode::CREATED,
        Err(_) => StatusCode::INTERNAL_SERVER_ERROR,
    }
}

#[tokio::main]
async fn main() {
    // Fail at startup, not on the first request, if the runtime isn't configured.
    encore::initialize();

    let app = Router::new().route("/users/:name", post(add_user));

    let addr = std::env::var("ENCORE_LISTEN_ADDR").unwrap_or_else(|_| {
        let port = std::env::var("PORT").unwrap_or_else(|_| "8080".to_string());
        format!("0.0.0.0:{port}")
    });
    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 last lines hand shutdown to Encore: the server stops on SIGTERM or SIGINT and drains its requests, then Encore drains Pub/Sub handlers and flushes telemetry. See [Graceful shutdown](/docs/rs/develop/shutdown).

## App layout

An Encore app is a directory with an `encore.app` file. Each service is a directory below it with an `encore.service.json` file, and for Rust, a Cargo package:

```
/my-app
├── encore.app
└── users                      // the users service
    ├── encore.service.json
    ├── Cargo.toml
    ├── migrations
    │   └── 1_create_users.up.sql
    └── src
        └── main.rs
```

`encore app new my-app --template rust` creates an app with one Rust service at its root, and `encore app init` makes an existing directory an app.

The service file names the service and sets `"lang": "rust"`:

```json
-- users/encore.service.json --
{
  "name": "users",
  "lang": "rust",
  "api": [
    { "type": "http", "prefix": "/", "name": "users", "expose": true }
  ]
}
```

The `api` entry tells Encore that the service serves HTTP itself under `/`, and `expose` routes requests from the API gateway to it. See [Services](/docs/rs/primitives/services) for every field, and for apps with several services or a Cargo workspace.

The package depends on `encore-dev`, and on Tokio and your web framework:

```toml
-- users/Cargo.toml --
[package]
name = "users"
version = "0.1.0"
edition = "2024"

[dependencies]
encore-dev = { path = "/path/to/encore-dev" }
axum = "0.7"
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros", "net"] }
```

> **Important**
>
> During early access, `encore-dev` is not published on crates.io. Add it as a `path` or `git` dependency pointing at the SDK source you were given. Keep the library name `encore`: the SDK's macros, such as `#[encore::test]`, refer to the crate by that name.

### Cargo features

The crate compiles only the infrastructure providers you need, since their clients account for most of its build time. None are on by default:

| Feature | What it adds |
|---|---|
| `local` | The providers `encore run` and `encore test` use: the local object storage emulator and Pub/Sub broker. |
| `aws` | S3 buckets and SNS/SQS Pub/Sub. |
| `gcp` | Cloud Storage buckets and Google Cloud Pub/Sub. |
| `protobuf` | Pub/Sub topics whose messages are Protocol Buffers. |

You don't enable the provider features yourself. `encore run` and `encore test` build with `local`, and `encore build` with the clouds it builds for, using the name your `Cargo.toml` gives the dependency. A service with a [custom run or test command](/docs/rs/primitives/services#custom-commands) has to pass `--features encore-dev/local` itself. Postgres, Redis, secrets and config need no feature.

## The runtime

The SDK starts its runtime on first use, from the configuration Encore passes to the process. If that fails, for example because the binary was started with `cargo run` instead of `encore run`, the process prints `encore: failed to initialize the SDK runtime` and exits.

Three functions control it:

- `encore::initialize()` starts the runtime right away, so a misconfigured service fails at startup. It also starts the Pub/Sub subscriptions declared with `#[encore::pubsub::register]`. Call it at the top of `main`.
- `encore::run_blocking()` starts the registered subscriptions, blocks until a shutdown signal, drains, and exits the process. It is for a service that serves no HTTP of its own, such as a Pub/Sub worker. Call it from a synchronous `main`, not from inside a Tokio runtime.
- `encore::tokio_handle()` returns a handle to the Tokio runtime the SDK's core runs its background work on, for spawning tasks onto it.

The SDK's methods are ordinary `async` functions. Your application brings its own Tokio runtime, typically with `#[tokio::main]`, and awaits them there.

A worker service with no HTTP server:

```rust
use encore::pubsub::{Message, Subscription, Topic};

static ORDERS: Topic<String> = Topic::new("order-placed");

#[encore::pubsub::register]
static FULFIL: Subscription<String> = Subscription::new(&ORDERS, "fulfil", fulfil);

async fn fulfil(msg: Message<String>) -> Result<(), encore::Error> {
    println!("fulfilling {}", msg.data);
    Ok(())
}

fn main() {
    encore::run_blocking();
}
```

## Running and testing

- `encore run` builds each service with `cargo build`, runs it with `cargo run`, provisions the infrastructure it declares, and rebuilds and restarts a service when its code changes.
- `encore test` runs `cargo test` in each service, with infrastructure of its own for every test. See [Testing](/docs/rs/develop/testing).
- `encore build` builds the services for deployment, with the cloud providers compiled in. See [Build Docker Images](/docs/self-host/build) for self-hosting.

See the [CLI reference](/docs/cli/cli-reference) for every command.

## The Encore.rs docs

**Primitives**

- [Services](/docs/rs/primitives/services): the service file, how Cargo packages map to services, and service URLs.
- [Databases](/docs/rs/primitives/databases): Postgres databases, migrations and queries.
- [Object Storage](/docs/rs/primitives/object-storage): buckets and objects.
- [Pub/Sub](/docs/rs/primitives/pubsub): topics, subscriptions and ordered delivery.
- [Cron Jobs](/docs/rs/primitives/cron-jobs): requests Encore makes of a service on a schedule.
- [Redis](/docs/rs/primitives/redis): Redis databases, transactions and scripts.
- [Secrets](/docs/rs/primitives/secrets): service, shared and global secrets.

**Develop**

- [Configuration](/docs/rs/develop/config): typed config values in files beside your code.
- [Metadata](/docs/rs/develop/metadata): the app's environment, build and deployment.
- [Testing](/docs/rs/develop/testing): isolated infrastructure per test, and fixtures.
- [Graceful shutdown](/docs/rs/develop/shutdown): draining requests and messages on shutdown.

**Observability**

- [Logging](/docs/rs/observability/logging): structured logs through the `log` crate.
- [Metrics](/docs/rs/observability/metrics): counters, gauges and histograms.
- [Tracing](/docs/rs/observability/tracing): your own spans in Encore's traces.
