What always-on means for an API with workers and schedules, how Railway and Render handle it, and how to run the same backend on ECS Fargate in your own AWS account.
Railway and Render deploy an API from a git push and add Postgres with a click, and a web service can stay up around the clock. The trouble starts with the parts around the API: a queue worker that must not miss messages, a nightly job that has to run on time, and a database you want backed up in an account you control.
Each platform answers those parts with its own settings: Render's free web services spin down after 15 minutes without inbound traffic, and Railway's Serverless setting marks a service inactive once it has sent no outbound traffic for 5 minutes, which in practice puts it to sleep between 5 and 10 minutes after its last outbound packet. Both limits are easy to hit by accident when a backend moves from a side project to something customers rely on.
This guide covers what an always-on backend needs, how Railway and Render provide it today, and how to run the same backend on ECS Fargate in your own AWS account, either with Encore or by hand.
The API should answer the first request of the morning as fast as the hundredth. Behind it, a backend usually has a worker that processes messages as they arrive and retries the ones that fail. It also has scheduled jobs that must run once per schedule, even during a deploy, and a Postgres database with backups and failover.
Deploys matter as much as uptime, since a new version should start, pass a health check and take traffic before the old one stops, which rules out setups where a deploy restarts the only instance.
Encore combines an open source infrastructure SDK for TypeScript and Go with a platform that provisions and deploys what the code declares into your own AWS or GCP account. The API, the worker, the schedule and the database are declared in the same service, and encore run starts Postgres locally alongside the API, so the whole backend runs on a laptop before it runs in AWS.

Here is an orders service with an endpoint, a receipt worker and a daily report. The subscriber is idempotent because Pub/Sub delivers at least once:
import { api } from "encore.dev/api";
import { SQLDatabase } from "encore.dev/storage/sqldb";
import { Topic, Subscription } from "encore.dev/pubsub";
import { CronJob } from "encore.dev/cron";
import log from "encore.dev/log";
const db = new SQLDatabase("orders", { migrations: "./migrations" });
interface OrderPlaced { orderId: number; email: string }
export const orderPlaced = new Topic<OrderPlaced>("order-placed", {
deliveryGuarantee: "at-least-once",
});
export const create = api(
{ expose: true, method: "POST", path: "/orders" },
async (p: { email: string; totalCents: number }): Promise<{ id: number }> => {
const row = await db.queryRow<{ id: number }>`
INSERT INTO orders (email, total_cents)
VALUES (${p.email}, ${p.totalCents}) RETURNING id`;
await orderPlaced.publish({ orderId: row!.id, email: p.email });
return { id: row!.id };
},
);
// The worker: runs for every published order, retried on failure.
new Subscription(orderPlaced, "send-receipt", {
handler: async (msg) => {
// Idempotent: a redelivered message inserts nothing.
const res = await db.queryRow<{ order_id: number }>`
INSERT INTO receipts (order_id) VALUES (${msg.orderId})
ON CONFLICT (order_id) DO NOTHING RETURNING order_id`;
if (res) log.info("receipt sent", { orderId: msg.orderId });
},
});
export const dailyReport = api({}, async (): Promise<{ orders: number }> => {
const row = await db.queryRow<{ n: number }>`
SELECT count(*)::int AS n FROM orders
WHERE created_at > now() - interval '1 day'`;
log.info("daily report", { orders: row!.n });
return { orders: row!.n };
});
new CronJob("daily-report", {
title: "Count the last day of orders",
schedule: "0 6 * * *",
endpoint: dailyReport,
});
Publishing after the insert leaves a small gap: if the process stops between the two calls, the order exists without its event. When every order must produce a receipt, write an outbox row in the same transaction as the order and publish from that table, so a crash cannot drop the event.
The migration creates orders and a receipts table with order_id as its primary key, which is what makes the ON CONFLICT clause turn a redelivery into a no-op. Running it locally and placing two orders looks like this:
Cron jobs do not run under encore run, so the report is triggered by calling its endpoint directly. The Pub/Sub and cron job docs cover retries, delivery guarantees and schedule syntax.
On deploy, Encore turns these declarations into resources in your AWS account. The service runs as Fargate tasks registered with Application Load Balancer target groups, the load balancer only routes to tasks that pass their health checks, and new versions roll out gradually while old tasks drain. The database becomes RDS Postgres, Multi-AZ with seven days of backups by default. The topic and subscription become SNS and SQS with a dead-letter queue for messages that keep failing, and Encore provisions an IAM role for the service. The Encore platform triggers the cron schedule, and there is no scheduler to set up in the account.
Where each part runs is configured per environment: Fargate or Kubernetes, and all services in one process or one per service, without changing the code.
encore run. The same bucket declaration is used in preview environments and production.Encore deploys into an AWS or GCP account you own, so you need one, and AWS bills the resources directly. Fargate tasks and a Multi-AZ RDS instance cost more than a single small platform instance, so a low-traffic side project is usually cheaper on Railway or Render. Cron jobs run only in deployed environments, not under encore run or in preview environments. Encore supports TypeScript and Go today, and you can sign up for early access to Python or Rust.
Run in your terminal to get started locally.
Railway runs each service as a long-lived container by default. Its Serverless setting, formerly App Sleeping, considers a service inactive after 5 minutes without outbound traffic and puts it to sleep between 5 and 10 minutes after the last outbound packet, since inactivity is sampled on an interval, and the first request after that can fail with a 502 or wait for a cold boot, according to the Railway Serverless docs checked on October 28, 2026. Open database pool connections count as outbound traffic and keep the service awake, so for APIs the setting is hard to predict, and a worker with an open pool never sleeps under it.
Background work on Railway is a second service in the same project that runs the worker command, and scheduled work is a cron service. A Railway cron job runs the service's start command on the schedule, expects the process to exit, skips a run if the previous one is still going, and cannot run more often than every 5 minutes, per the Railway cron docs on the same date. Compute is billed at about $20 per vCPU per month and $10 per GB of memory per month (Railway pricing page, October 28, 2026).
Railway is a better fit than Encore for a team that wants the quickest path from repository to a running service in any language, with usage-based billing, and is fine with the data living in Railway's infrastructure. Pull request environments and a project canvas that shows every service and connection make it easy to work with for small teams. The Railway alternatives guide compares the options for teams that outgrow it.
Render's free web services spin down after 15 minutes without inbound traffic and take about a minute to spin back up, and free Postgres databases expire after 30 days, according to Render's free instance docs on October 28, 2026.
A Render backend with a worker is two services in a render.yaml Blueprint: a web service and a worker, each with its own build command, start command and plan, plus a cron service with a schedule for recurring jobs. Each one is billed as its own instance. Attaching a persistent disk to a service turns off zero-downtime deploys for it, so file uploads usually move to object storage once a backend matters.
Render is a better fit than Encore for teams that do not want to own a cloud account, want clear per-service pricing and preview environments, and want web services that switch to a new version only after it passes its health check. The Render alternatives guide and Render vs Railway cover the platform in more depth.
Running the same backend directly on AWS means an ECS service on Fargate for the API, a second ECS service that polls SQS for the worker, RDS for Postgres and EventBridge Scheduler for the daily report. AWS now offers ECS Express Mode, which creates the Fargate service, a load balancer with TLS, auto scaling and networking from a container image, with no charge beyond the resources it creates.
Express Mode is aimed at stateless web applications and APIs, and the database, queue, dead-letter queue, scheduler and the IAM grants between them are still separate resources to define, usually in Terraform or CloudFormation. The worker needs its own task definition with permission to read from the queue, and the schedule needs a role that can start a task or call the API. Teams that already run Terraform for the rest of their AWS estate often prefer this route because every resource sits in their own modules. It is a better fit than Encore when a platform team wants full control over VPC layout, IAM policies and deployment settings with nothing between them and AWS, and has the time to write and maintain those modules.
encore run.To move an existing app, see how to migrate from Render to AWS or how to migrate from Railway to AWS. If the job is mainly receiving webhooks and processing them in the background, hosting a webhook worker on AWS covers that case.
Both can keep a web service running around the clock, and the difference shows up in the extra pieces. On Railway the Serverless setting must stay off and cron services must exit after each run, with runs at least 5 minutes apart. On Render the free tier spins web services down after 15 minutes without traffic, while workers and cron jobs are separate services, each billed and configured on its own. If the backend should run in your own AWS account, neither platform deploys it there by default.
Run the API as an ECS service on Fargate behind an Application Load Balancer, with RDS for Postgres, SQS for background work and a scheduler for recurring jobs. With Encore you declare the API, the SQLDatabase, a Topic with a Subscription and a CronJob in TypeScript, test them with encore run, and Encore provisions Fargate, RDS, SNS and SQS in your AWS account when you deploy.
No. An ECS service keeps its desired number of tasks running whether or not requests arrive, and the load balancer only routes traffic to tasks that pass their health checks. Billing is per running task, which is the cost of never having a cold start.
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.