A single VPS running Docker Compose is still a solid way to ship a small backend. Where that model wins, where multi-AZ managed cloud takes over, and how Encore deploys the same app to your own AWS or GCP account when one box is no longer enough.
A VPS with Docker and Compose is how many backends still go live: one virtual machine, a docker-compose.yml, a reverse proxy and a nightly backup of the volume. The bill is predictable, SSH is enough to debug, and there is no cluster control plane to learn.
That setup stops being enough when the database needs failover, when a deploy cannot bounce every container at once, or when a second region and private networking become requirements rather than nice-to-haves. This guide covers when the box wins, what changes on managed cloud, and how Encore takes the same application into your own AWS or GCP account when you outgrow one machine.
One box wins on clarity because Compose describes the app, the worker, Postgres and Redis in a file every developer already knows, deploys are docker compose pull && docker compose up -d, and hosting from Hetzner, DigitalOcean, Linode or a Lightsail instance stays cheap for modest traffic. For a side project, an MVP or an internal admin that a handful of people use during business hours, that trade is often correct.
You can harden it without leaving the model: put Postgres on a second volume with snapshots, terminate TLS at Caddy or Traefik, restrict SSH with keys and fail2ban, and keep Compose profiles so staging and production differ only by env files. Plenty of apps stay here longer than Twitter threads suggest, especially when the alternative is weeks of IAM and VPC work for an app that still fits in 2 GB of RAM.
The failure domain is the instance: a provider maintenance window, a full disk or a bad kernel update takes the API and the database down together. Restoring from a snapshot is a drill you must practice; it is not the same as a multi-AZ managed database with automated failover.
Deploys and scaling share the same limit, since Compose can run several replicas of the API on one host and they still compete for the same CPU, memory and disk, and a compose recreate still restarts containers on that host. Workers that need to scale independently of the HTTP tier push you toward a second machine and then toward shared networking, shared secrets and a real load balancer.
Compliance and enterprise buyers often expect private subnets, short-lived cloud credentials and managed encryption at rest. A public VPS with Docker can be secured carefully, and it rarely matches the checklist those reviews use for AWS or GCP accounts.
On AWS or GCP the Compose services become separate products: containers on ECS Fargate, Cloud Run or Kubernetes, Postgres on RDS or Cloud SQL, object storage on S3 or GCS, and messaging on SQS, SNS or Pub/Sub. You gain Availability Zones, automated backups and scaling knobs per service, and you take on VPC design, IAM roles, image registries and a pipeline that builds and rolls out new tasks.
That translation, from Compose services to IAM, networking and managed services, is what leaving the VPS costs, and teams either write it in Terraform or CDK, adopt a platform that generates it, or stay on the box until the risk of a single disk is higher than the cost of the move. AWS Lightsail and similar products sit in between for a while, then hit the same wall when you need the rest of the cloud catalog.
Encore works alongside the frameworks and services you already have in mind, and the resources you declare are infrastructure from code. The platform provisions and deploys into your own AWS or GCP account: you keep writing ordinary TypeScript or Go handlers, declare Postgres, object storage, Pub/Sub, caches, cron jobs and secrets in the same repo, and Encore provisions the managed equivalents in your account when you connect your cloud, as covered in the AWS infrastructure docs.

Run in your terminal to get started locally.
A typical VPS Compose stack of API, Postgres and file uploads becomes a service with a database and a bucket:
// media/encore.service.ts
import { Service } from "encore.dev/service";
export default new Service("media");
// media/media.ts
import { api } from "encore.dev/api";
import { SQLDatabase } from "encore.dev/storage/sqldb";
import { Bucket } from "encore.dev/storage/objects";
const db = new SQLDatabase("media", { migrations: "./migrations" });
const uploads = new Bucket("uploads", { versioned: false });
export const register = api(
{ expose: true, method: "POST", path: "/files" },
async ({ name }: { name: string }): Promise<{ id: number }> => {
const row = await db.queryRow<{ id: number }>`
INSERT INTO files (name) VALUES (${name}) RETURNING id`;
return { id: row!.id };
},
);
export const uploadUrl = api(
{ expose: true, method: "POST", path: "/files/:id/upload-url" },
async ({ id }: { id: number }): Promise<{ url: string }> => {
const url = await uploads.signedUploadUrl(`files/${id}`, { ttl: 900 });
return { url };
},
);
-- media/migrations/1_create_files.up.sql
CREATE TABLE files (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
encore run starts Postgres locally and uses a local object store, so the flow works on a laptop without Compose. On deploy, Encore creates managed Postgres and object storage in your account and provisions an IAM role for the service. The object storage docs and database docs cover the APIs, and encore build docker still produces a container image when you need one outside that path.
When an AI coding agent adds a second bucket or a worker subscription, it edits the same application package, runs it locally with encore run, and the next deploy creates the matching cloud resources instead of another Compose service on a fuller disk.
Best fit: Teams leaving a single Docker VPS for managed Postgres, object storage and containers in their own AWS or GCP account, without rebuilding the app around Terraform modules first.
Yes for a small API, an internal tool or an early product where a few minutes of downtime on deploy or reboot is acceptable. You still own OS patches, disk backups, TLS renewal and what happens when the instance or the provider region fails.
Move when you need a second Availability Zone, managed database failover, independent scaling of API and workers, or compliance that expects private subnets and short-lived credentials. Those requirements usually mean a cloud account with load balancers and managed data services rather than a larger VPS.
Compose on one VPS keeps networking and deploys simple and cheap. Managed cloud splits the app, database, cache and queue onto separate services with backups and scaling, at the cost of VPC, IAM and deploy plumbing you either write or generate.
With Encore, declare services, Postgres, queues and object storage in TypeScript or Go next to the code that uses them, connect your AWS or GCP account and deploy. Encore provisions the managed resources and runs the containers in your account, and encore build docker can still produce an image when you need one for another path.
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.