Nov 6, 20267 min read

What Is AWS Lambda? Serverless Functions Explained for Backends

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.

AWS Lambda at a glance

ConceptWhat it isWhat to decide
Event FunctionHandler invoked per event or requestTrigger, runtime, memory, timeout
Execution environmentIsolated runtime that may be reused (warm start)Init cost vs provisioned concurrency
Event sourceAPI Gateway, Function URL, S3, SQS, EventBridge, and many othersSync vs async, batching, retries
TimeoutMax run time per invocation (up to 15 minutes)Fail fast vs long jobs elsewhere
Memory / CPU128 MB to 10,240 MB; CPU scales with memoryLatency vs cost
ConcurrencyHow many environments run in parallel (account and function limits)Reserved vs provisioned concurrency
Always-on alternativeContainers or services that stay upEncore services on Fargate in your account

How Lambda Event Functions work

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.

Cold starts and concurrency

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.

Event sources backends actually use

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.

What a hand-built Lambda backend involves

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.

When always-on services win

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.

How Encore runs services on your AWS

Encore

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.

The Infrastructure page in the Encore dashboard with a database's configuration panel open, showing fields for vCPUs, memory, storage, availability type, max connections and backups.
Each provisioned resource can be reviewed and its configuration edited per environment in the Encore dashboard. The screenshot shows a GCP Cloud SQL database.

Set up the app

Get started
brew install encoredev/tap/encore &&
encore app create
Copy

Run in your terminal to get started locally.

~
$ encore app create checkout --example=go/hello-world$ cd checkout && mkdir -p checkout/migrations

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.

Good to know

  • Keep Lambda handlers idempotent; at-least-once delivery is common for async and queue sources.
  • VPC-attached functions add ENI cold-start cost; place them in private subnets only when they must reach private resources.
  • The 15 minute ceiling pushes longer work to Step Functions, ECS tasks or an always-on worker.

Frequently asked questions

What is AWS Lambda used for?

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.

What is a Lambda cold start?

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.

What is the maximum Lambda timeout?

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.

When should I use always-on services instead of Lambda?

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.

How do I run a Go or TypeScript API with Postgres and queues on AWS without wiring each Lambda 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.

~/orders — claude
Claude Code
Claude Code v2.1.180Opus 5.5~/orders