Understanding Encore
How application code becomes running infrastructure
Encore is a platform for automating infrastructure from local development to cloud deployment. Instead of describing application architecture in separate infrastructure files, you declare services, APIs, and infrastructure resources in application code. Encore uses those declarations to run the application locally, validate it, and provision the infrastructure it needs in each environment.
The link between those capabilities is the Encore Application Model: a description of your application's services, APIs, resources, and the relationships between them. Encore derives the model from static analysis of your source code, without running it.
Encore runs a declared SQL database as a Postgres container locally and provisions it as RDS or Cloud SQL in the cloud. A declared Pub/Sub topic runs on a local broker, then on SNS and SQS or Google Cloud Pub/Sub, and so on.
The core idea
Consider this declaration of a SQL database, one of Encore's infrastructure primitives for TypeScript or Go:
const db = new SQLDatabase("orders", { migrations: "./migrations" });
From this declaration, the parser records the database name and its migration directory. As it analyzes the rest of the application, it also records which services query the database.
Running encore run creates a Postgres database in a local container. When deploying with Encore's cloud platform, Encore provisions a managed Postgres instance and applies the same migrations. See Development workflow for using the same declaration across local, preview, and production environments.
Encore rebuilds the model from source on every encore run and every build, keeping it synchronized with the code it describes. During the build, the parser validates the resource declarations it discovers and reports invalid declarations. The SDK, parser and compiler that produce the model are all Open Source.
The development dashboard renders the model as an architecture diagram, where each box represents a service and shows its public, authenticated, and private endpoints and the databases it uses. Hovering over a service highlights its callers, API calls, and resource dependencies:
What the model enables
Because Encore understands the application rather than only its deployment configuration, the same model supports the whole development workflow:
- Local infrastructure:
encore runstarts local implementations of declared resources without a separate Docker Compose or emulator configuration. - Build-time validation: the compiler reports invalid declarations and resource usage before deployment.
- Development tooling: the local dashboard provides API documentation, architecture diagrams, logs, traces, and a database explorer.
- Type-safe communication: Encore validates API schemas and generates clients for calling services and frontends.
- Cloud provisioning: deployments create the matching managed services in AWS or GCP and apply environment-specific capacity, networking, and backup settings.
- Least-privilege access: resource usage determines which services can call an API or access a database, bucket, or topic.
The open source SDKs, parser, compiler, CLI, and runtime provide the application model, local development, testing, and self-hosted builds. Encore's managed platform adds cloud provisioning, deployments, preview environments, and operational tooling in your own AWS or GCP account. You can use infrastructure outside the model alongside either approach.
Inside the model
- Services, and the directory or package each one lives in
- API endpoints, with the full type schema of every request and response
- SQL databases and their migration directories
- Pub/Sub topics and subscriptions
- Cron jobs, object storage buckets, caches and secrets
- Middleware and API gateways
Running a build without supplying infrastructure configuration prints the part of the model that has to be satisfied:
$ encore build docker myapp:latest
Your infra configuration is incomplete
Missing Resource Configurations:
Secrets : SlackWebhookURL
Databases : monitor, site
Subscriptions: uptime-transition/slack-notification, site.added/check-site
Topics : uptime-transition, site.added
Deriving IAM and configuration
The model records how resources are used. Encore uses this information to derive IAM permissions and other configuration. For example, two services may use the same uploads bucket:
// in the ingest service
await uploads.upload("q3.csv", csvBytes);
// in the reports service
const csv = await uploads.download("q3.csv");
The parser records the download in reports and the upload in ingest. Encore grants reports read access to the bucket and ingest write access. Bucket usage distinguishes operations such as reading object contents, accessing metadata, and generating signed upload URLs. The model also records which services publish to each topic and call each endpoint.
The model drives provisioning, request validation against the declared schemas, generated clients, API documentation, and distributed tracing across service boundaries. These features use the application model as their shared source of service, resource, and schema information.
Requirements on your code
Resource declarations are read from your source without running it, which constrains how you write them.
Names must be string literals
A name assembled from a variable or a template fails the build:
const regions = ["eu", "us", "ap"];
export const orderTopics = regions.map(
(r) => new Topic<string>(`orders-${r}`, { deliveryGuarantee: "at-least-once" }),
);
error: expected string literal
--> orders/topics.ts:5:10
|
5 | (r) => new Topic<string>(`orders-${r}`, { deliveryGuarantee: "at-least-once" }),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Declarations must be assigned at module scope
The parser collects top-level bindings. Constructor calls inside functions, conditionals, or loops are not included in the application model:
if (process.env.SHARD) {
// Not part of the model, so never provisioned.
new SQLDatabase("shard", { migrations: "./migrations" });
}
API endpoint declarations must be exported. Service definitions must be the module's default export.
Infrastructure outside the model
The application model supports a fixed set of resource types. Other infrastructure and third-party services are not included in the model. Provision resources such as search clusters or queues determined at runtime separately, connect to them as external dependencies, and store their connection details in a secret:
import { secret } from "encore.dev/config";
const searchEndpoint = secret("SearchEndpoint");
export const search = api(
{ expose: true, method: "GET", path: "/search" },
async ({ q }: { q: string }): Promise<Results> => {
const resp = await fetch(`${searchEndpoint()}/query?q=${q}`);
return resp.json();
},
);
Encore knows about the secret and the endpoint that uses it, so both appear in the model, while the cluster behind the endpoint does not.
The Terraform Provider also exposes data sources for infrastructure provisioned by Encore, allowing existing Terraform configurations to reference an Encore database or topic by name.