Back to Blog
Tutorial11 min read2026-06-29

How to Deploy an Encore.ts Backend to Production

Encore.ts is a backend framework with built-in infrastructure primitives and a high-performance Rust runtime. Learn how to self-host an Encore.ts backend in a Docker container with PostgreSQL.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

Encore.ts is a TypeScript backend framework with an unusual proposition: you declare infrastructure (databases, pub/sub, cron jobs, secrets) as code in your application, and Encore wires it up. It pairs a TypeScript API layer with a high-performance Rust runtime that handles request processing. While Encore offers its own cloud, you can also self-host. This guide covers building an Encore.ts backend into a Docker container and deploying it with a managed PostgreSQL database.

How Encore.ts is structured

Encore apps are organized into services. You define APIs as typed functions, and Encore generates request validation, routing, and client SDKs from the types. Infrastructure is declared inline:

import { api } from "encore.dev/api";
import { SQLDatabase } from "encore.dev/storage/sqldb";

const db = new SQLDatabase("app", { migrations: "./migrations" });

export const getUser = api(
  { method: "GET", path: "/users/:id", expose: true },
  async ({ id }: { id: number }): Promise<{ name: string }> => {
    const row = await db.queryRow`SELECT name FROM users WHERE id = ${id}`;
    return { name: row?.name ?? "" };
  }
);

The SQLDatabase declaration and the typed api function are the framework's core ideas — infrastructure and API contracts as code.

Self-hosting: encore build docker

Encore provides a command to produce a standalone Docker image for self-hosting:

encore build docker my-app:latest

This builds an image containing your compiled backend and the Encore runtime. The image is what you deploy to any container platform.

Configuring infrastructure for self-hosting

When self-hosting, Encore needs to know how to connect to real infrastructure (your database, secrets) rather than the managed Encore Cloud. You provide this via an infrastructure config file referenced by the ENCORE_RUNTIME_CONFIG or the --config mechanism. A minimal infra config maps your declared database to a real connection:

{
  "sql_servers": [
    {
      "host": "<db-host>:5432",
      "databases": {
        "app": {
          "username": "<user>",
          "password": {"$env": "DB_PASSWORD"}
        }
      }
    }
  ]
}

The {"$env": "DB_PASSWORD"} form pulls the password from an environment variable, so secrets aren't in the file. Mount or bake this config and point Encore at it.

Wiring up a managed PostgreSQL

Link a managed PostgreSQL instance. You'll get connection details (host, port, database, user, password) — and on PandaStack a DATABASE_URL is injected. Map those into the infra config above (host, user, and DB_PASSWORD from the connection details). Encore's app database declaration then connects to your managed instance.

The Dockerfile approach

If you prefer a hand-written Dockerfile over encore build docker, a typical setup builds the app and runs the Encore runtime. But the supported path for self-hosting is encore build docker, which produces a correct image including the Rust runtime. Wrap it in your CI or run it during the platform build:

encore build docker --config ./infra-config.json my-app:latest

The resulting image listens on a port (configurable) — set it to the injected PORT via the runtime config so the platform's ingress reaches it.

Migrations

Encore manages migrations from the ./migrations directory you declared on the SQLDatabase. When self-hosting, Encore applies pending migrations on startup against the configured database. Because this runs at boot, be cautious with multiple replicas — Encore coordinates this, but for safety in a multi-replica rollout, confirm your version's migration behavior or run an initial single-replica deploy to apply migrations.

Environment variables and secrets

VariablePurpose
PORTlisten port (via runtime config)
DB_PASSWORDdatabase password referenced by infra config
Encore secretsset via the infra config / env for secret() values

Encore has a first-class secret() primitive. When self-hosting, secrets are supplied through the infra configuration and environment, keeping them out of source.

Health checks

Expose a lightweight API endpoint that returns 200 and point the platform's readiness probe at it. Keep it free of database access so the liveness check stays cheap:

export const health = api(
  { method: "GET", path: "/health", expose: true },
  async (): Promise<{ status: string }> => ({ status: "ok" })
);

Deploying

Produce the image with encore build docker, provide the infra config pointing at your managed PostgreSQL, and deploy as a container web service. Set DB_PASSWORD and any secrets, link the database, and ensure the runtime listens on the injected PORT. Live logs confirm the runtime started, migrations applied, and the DB connected.

encore build docker --config ./infra-config.json my-app:latest

Encore's tradeoffs

Encore.ts is opinionated: its infrastructure-as-code model and Rust runtime deliver strong performance and developer ergonomics, but self-hosting requires the infra config step that the managed cloud handles for you. As a newer framework, check the current docs for the exact self-hosting flags — they've evolved. The payoff is a backend where infrastructure, validation, and typing are unified.

Conclusion

Self-hosting Encore.ts means building with encore build docker, supplying an infra config that maps your declared database to a managed PostgreSQL, sourcing secrets from env, and listening on the injected PORT. The framework's infrastructure-as-code approach is its defining strength.

Try self-hosting an Encore.ts backend with a managed PostgreSQL on PandaStack's free tier — get started at [dashboard.pandastack.io](https://dashboard.pandastack.io).

References

  • [Encore.ts Documentation](https://encore.dev/docs/ts)
  • [Encore: Self-hosting with Docker](https://encore.dev/docs/ts/self-host/build)
  • [Encore: Infrastructure Configuration](https://encore.dev/docs/ts/self-host/configure-infra)
  • [Encore: SQL Databases](https://encore.dev/docs/ts/primitives/databases)
  • [Encore: Secrets](https://encore.dev/docs/ts/primitives/secrets)

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also