AWS Lambda runs code in response to events without you managing servers. How Event Functions, cold starts and event sources work, when always-on services win, and how Encore runs backend services on your AWS account from infrastructure declared in code.
AWS Lambda is AWS's serverless compute service: you ship a handler, attach triggers, and AWS runs the code when events arrive without you patching servers. For backends that means HTTP via API Gateway or Function URLs, stream and queue consumers, object notifications and scheduled jobs, billed per request and GB-second.
Creating a function is quick, and the decisions that matter are which event sources you bind, how cold starts and concurrency behave, and when an always-on service with a connection pool is a better shape than one function per trigger. This guide covers those pieces for classic Lambda Event Functions and how Encore runs backend services on your AWS from infrastructure declared in code. Language-specific packaging and runtimes are covered separately; this page stays on how Lambda works and when always-on services fit better.
You upload a deployment package (zip or container image), choose a runtime or a custom provided runtime, set memory and timeout, then grant the function an execution role. On invoke, Lambda places the event into an execution environment, runs your handler, and returns the result for synchronous invokes or queues retries for asynchronous ones.
AWS documents Lambda Event Functions as the original request and response model, distinct from newer Lambda Web Functions (HTTP servers that listen on a port) and Lambda MicroVMs. Most backend articles still mean Event Functions when they say "Lambda": one concurrent request per environment by default, scale by adding environments, pay for duration. Web Functions and MicroVMs solve different shapes; this guide stays on Event Functions.
Quotas that backends hit early include the 15 minute timeout, 6 MB synchronous payload limit, account concurrency (1,000 concurrent executions by default, increasable), and the 50 MB zip upload limit through the API (larger packages go through S3). CPU power rises with memory; at about 1,769 MB you get the equivalent of one vCPU.
A cold start is the time to create an environment: pull code, start the runtime, run package-level init, then enter the handler. Warm starts reuse that environment for later invokes. AWS notes cold starts are usually a small share of invocations, and latency still ranges from under 100 ms to well over a second depending on runtime, package size, VPC ENI attachment and init work.
Provisioned concurrency keeps a set of environments initialized so latency-sensitive paths avoid cold starts, at a steady cost. SnapStart (where supported) snapshots initialized environments to shorten restore time. Putting heavy clients in init helps warm invokes and makes cold invokes pay that cost once per environment.
Concurrency is the number of environments executing at once, and burst scaling plus reserved concurrency shape how fast a function can absorb a spike and whether it starves other functions in the account. Event source mappings for streams and queues poll and invoke in batches; when concurrency is exhausted, processing slows or throttles rather than opening unbounded environments.
HTTP fronts are API Gateway or a Lambda Function URL. Function URLs suit simple HTTPS endpoints; API Gateway adds routing, auth integrations, usage plans and request validation. Object workflows use S3 notifications; queues use SQS event source mappings; schedules and SaaS fan-in use EventBridge; DynamoDB and Kinesis use stream mappings.
Each source brings its own retry and failure story: synchronous HTTP returns errors to the caller, asynchronous invokes retry and can land on a dead-letter queue or failure destination, and stream mappings checkpoint progress. Designing idempotent handlers matters more than on a single always-on process that owns its in-memory state.
A typical production setup has one function (or more) per trigger family, an execution role with least-privilege policies, environment variables or Secrets Manager for config, a packaging pipeline that builds language-specific artifacts, IAM for every upstream service, local emulation or contract tests because the actual event shapes only appear in AWS, and often RDS Proxy or another pooler if functions open database connections. Terraform or SAM/CDK repeats that wiring for every new endpoint and queue.
Spiky image transforms, webhook receivers and nightly fan-out jobs fit that model well. A product API that needs a stable Postgres pool, several collaborating services, cron and object storage usually spends more time on glue than on handlers.
Always-on containers (ECS Fargate, Cloud Run, Kubernetes) keep processes warm, hold connection pools and serve steady traffic without a cold-start tax on every scale-from-zero. They suit multi-minute work that would need Step Functions or chained Lambdas, WebSockets, and codebases that think in services rather than one handler file per event type.
Lambda remains a strong fit for sparse events and glue between AWS services. The mistake is forcing an entire domain backend into functions when the team already wants long-lived services on their own VPC.
APIs and resources you declare in Encore are infrastructure from code, and the platform provisions and deploys them into your own AWS or GCP account. You declare APIs, Postgres, Pub/Sub, object storage, cron jobs and secrets in application code. On AWS, Encore runs those services on Fargate by default (or EKS if you choose it), creates the matching managed resources, and provisions an IAM role for the service, as listed in the AWS infrastructure docs. Encore does not claim to run your app as Lambda Event Functions.

Run in your terminal to get started locally.
A checkout service with an HTTP API, Postgres and a Pub/Sub topic replaces a set of Lambda handlers plus separately wired SQS and RDS:
// checkout/checkout.go
package checkout
import (
"context"
"encore.dev/pubsub"
"encore.dev/storage/sqldb"
)
var db = sqldb.NewDatabase("checkout", sqldb.DatabaseConfig{
Migrations: "./migrations",
})
type OrderPaid struct {
OrderID string `json:"order_id"`
}
var OrderPaidEvents = pubsub.NewTopic[*OrderPaid]("order-paid", pubsub.TopicConfig{
DeliveryGuarantee: pubsub.AtLeastOnce,
})
type PayParams struct {
OrderID string `json:"order_id"`
}
type PayResponse struct {
OK bool `json:"ok"`
}
//encore:api public method=POST path=/checkout/pay
func Pay(ctx context.Context, p *PayParams) (*PayResponse, error) {
_, err := db.Exec(ctx, `
INSERT INTO payment_attempt (order_id) VALUES ($1)
`, p.OrderID)
if err != nil {
return nil, err
}
if _, err := OrderPaidEvents.Publish(ctx, &OrderPaid{OrderID: p.OrderID}); err != nil {
return nil, err
}
return &PayResponse{OK: true}, nil
}
encore run starts Postgres locally and delivers Pub/Sub in-process for development. Cron jobs do not run locally. On deploy, Encore creates the Fargate service, the database and the SNS/SQS topology behind the topic, with the service reaching AWS APIs through its IAM role. Pub/Sub details are in the Go Pub/Sub docs and deploy path in deploy to your own cloud.
An AI coding agent can add another topic or endpoint in the same package and verify it with encore run before the change lands in your AWS account.
Best fit: Teams building product APIs on AWS who want always-on services plus Postgres, queues, cron and secrets declared in code rather than one Lambda per trigger.
AWS Lambda runs short-lived functions in response to events such as HTTP calls through API Gateway, object uploads in S3, messages on SQS, or schedules on EventBridge. Backends use it for spiky, event-driven work where paying per invocation beats keeping servers warm.
A cold start is the extra latency when Lambda creates a new execution environment before your handler runs: downloading the code, starting the runtime and running init. Warm starts reuse an existing environment. Provisioned concurrency and SnapStart reduce cold-start impact for latency-sensitive paths.
A standard Lambda Event Function can run for up to 15 minutes (900 seconds) per invocation. Memory ranges from 128 MB to 10,240 MB. Synchronous request and response payloads are capped at 6 MB each.
Prefer always-on containers or services when you need long-lived connection pools to Postgres, multi-minute workflows beyond a single invocation, WebSockets or steady low-latency APIs where cold starts hurt, or a multi-service backend with queues and cron that you want to reason about as processes rather than one function per trigger.
With Encore, declare APIs, sqldb or SQLDatabase, Pub/Sub topics and cron in application code, connect your AWS account and deploy. Encore runs the services on Fargate in your account, provisions the resources and an IAM role for the service, while encore run starts Postgres locally for development.
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.