How to Build an AWS Lambda API: 12 Steps, 60 Min [2026]

AWS Lambda turned ten in 2025, and 2026 has been its busiest year of updates yet. AWS added .NET 10 support in January, raised the asynchronous payload limit from 256 KB to 1 MB in the first quarter, and pushed Lambda Managed Instances, with up to 32 GB of memory, three times the standard ceiling, into general availability by the second quarter. Response streaming is now live in every commercial AWS Region. None of that matters much, though, if you have never actually deployed an AWS Lambda function that does real work.

This tutorial builds a working serverless REST API from a blank AWS account: a task-management backend with five endpoints, backed by DynamoDB, fronted by Amazon API Gateway, and secured with a least-privilege IAM role. You write the Python handler yourself, deploy it with the AWS CLI, then redeploy it with AWS SAM, and finish with a stack you can actually extend. Budget about 60 minutes if you already have an AWS account, closer to 90 if you are setting one up for the first time.

Google · Preferred Sources

Don't miss new tech stories on Google

Add Tech Insider once in the Google app and our stories appear in your news suggestions.

Add Now

What You’ll Build in This Tutorial

By the end of this guide you will have a working Task Manager API running entirely on managed AWS services, with no servers to patch and no idle compute to pay for. The project follows the same pattern most production serverless APIs use in 2026: a single AWS Lambda function handling multiple routes, a DynamoDB table for storage, and API Gateway acting as the front door.

Your finished API will expose five routes:

  • POST /tasks creates a new task
  • GET /tasks lists every task
  • GET /tasks/{id} retrieves a single task
  • PUT /tasks/{id} updates a task
  • DELETE /tasks/{id} removes a task

The stack behind those routes: one Lambda function running Python 3.13, a DynamoDB table in on-demand mode, an API Gateway REST API using Lambda proxy integration, an IAM role scoped to exactly the permissions the function needs, and an AWS SAM template that redeploys the whole thing with a single command. Every piece maps to a real production pattern, not a simplified version you will have to rebuild later once traffic shows up.

Prerequisites: Tools, Accounts, and Versions You Need

Install and confirm each item below before starting Step 1. Version mismatches are the most common reason a tutorial like this breaks halfway through.

ToolVersionPurposeCheck Command
AWS accountActive, billing enabledHosts every resource you createN/A
AWS CLIv2 (latest)Deploys Lambda, API Gateway, and DynamoDB from the terminalaws --version
Python3.13Local testing and the Lambda runtime itselfpython3 --version
AWS SAM CLILatest versionDeploys the full stack from one template in Step 10sam --version
IAM permissionsAdministrator or scoped policyCreate roles, functions, APIs, and tablesN/A
Code editorAnyWrite lambda_function.py and template.yamlN/A

If you have never installed the AWS CLI, grab it from the official AWS documentation and run aws configure once you have an access key. A free-tier AWS account covers this entire tutorial. The resources you create here fall well inside the 1 million monthly Lambda requests, 400,000 GB-seconds of compute, and 25 GB of DynamoDB storage that AWS includes at no charge, according to AWS’s published Lambda pricing.

How AWS Lambda and API Gateway Fit Together

Before writing code, it helps to know what each service actually does. Skipping this part is why so many people get stuck between Step 6 and Step 7, staring at a 502 error with no idea which service caused it.

The Core Components

Four services do all the work in this tutorial. Lambda runs your code on demand and charges only for the milliseconds it executes. API Gateway receives HTTPS requests, matches them to a route, and forwards each one to Lambda as a structured JSON event. DynamoDB stores your task records as key-value items with single-digit-millisecond reads. IAM issues the role that lets Lambda talk to DynamoDB and write logs, and without it every database call fails with an access-denied error.

Requests flow in one direction. A client sends an HTTPS request to API Gateway, API Gateway packages it as an event and invokes Lambda, Lambda runs your handler and returns a JSON response, and API Gateway translates that response back into an HTTP reply. The round trip typically finishes in under 200 milliseconds once a function is warm.

REST API vs HTTP API vs Lambda Function URLs

API Gateway offers three ways to expose an AWS Lambda function, and picking the wrong one costs time later. REST APIs, the type this tutorial uses, support usage plans, API keys, request validation, and resource policies, which makes them the standard choice for a production API you plan to secure and meter. HTTP APIs trade some of those features for lower latency and a lower price per million calls, which suits internal or high-volume traffic. Lambda function URLs skip API Gateway entirely and give a function its own HTTPS endpoint, the fastest option to set up but without the throttling or API-key controls Step 9 relies on.

What’s New in AWS Lambda for 2026

A few 2026 changes are worth knowing before you start, because they affect decisions you will make in later steps. AWS’s Q2 2026 serverless roundup confirmed that Lambda Managed Instances now support up to 32 GB of memory, three times the standard 10,240 MB ceiling, aimed at steady, memory-heavy workloads rather than bursty ones. The same update made response streaming available in every commercial AWS Region and brought the Lambda durable functions SDK for Java to general availability, joining Python and TypeScript.

Earlier in the year, AWS’s Q1 2026 roundup raised the maximum payload for asynchronous Lambda invocations, Amazon SQS, and EventBridge from 256 KB to 1 MB, and a January 2026 weekly roundup added .NET 10 as a managed runtime and container base image. AWS also introduced Lambda MicroVMs this year, isolated and stateful execution environments built for user- or AI-generated code, with sessions that can persist for up to 8 hours. None of these are required for the Task Manager API you are about to build, but they matter once you outgrow the basics, and this guide points back to them in the advanced tips section.

Step 1: Create an AWS Account and Configure the CLI

If you already have an AWS account and a configured CLI profile, skip to Step 2. Otherwise, sign up at aws.amazon.com, create an IAM user with programmatic access instead of using your root account, and generate an access key pair for that user. Root credentials should never touch a terminal.

Once the AWS CLI is installed, run aws configure and paste in your access key, secret key, and preferred region. Confirm everything works with a single identity check.

$ aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: ****************EXAMPLE
Default region name [None]: us-east-1
Default output format [None]: json

$ aws sts get-caller-identity
{
    "UserId": "AIDAEXAMPLE123456",
    "Account": "123456789012",
    "Arn": "arn:aws:iam::123456789012:user/your-username"
}

If that command returns your account ID instead of an error, the CLI is authenticated and ready for every step that follows.

Step 2: Set Up an IAM Role With Least-Privilege Permissions

Lambda needs an execution role before it can run. Resist the urge to attach a broad managed policy to save time. Create a role that trusts only the Lambda service, then attach exactly the permissions the Task Manager function needs: basic execution logging and access to one DynamoDB table.

// trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "Service": "lambda.amazonaws.com" },
      "Action": "sts:AssumeRole"
    }
  ]
}
$ aws iam create-role \
  --role-name task-manager-lambda-role \
  --assume-role-policy-document file://trust-policy.json

$ aws iam attach-role-policy \
  --role-name task-manager-lambda-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

$ aws iam put-role-policy \
  --role-name task-manager-lambda-role \
  --policy-name DynamoDBTaskAccess \
  --policy-document file://dynamodb-policy.json

The dynamodb-policy.json file referenced above should list only the five actions the function actually calls: PutItem, GetItem, UpdateItem, DeleteItem, and Scan, scoped to the ARN of the tasks table you create in Step 8. That scoping is what turns “it works” into “it works and can’t be abused if the function is ever compromised.”

Step 3: Write Your First AWS Lambda Function

This is the core of the tutorial: a single Python handler that routes all five endpoints based on the HTTP method and path parameters API Gateway sends it. Save this as lambda_function.py.

import json
import os
import uuid
import boto3

dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table(os.environ["TABLE_NAME"])


def handler(event, context):
    method = event["httpMethod"]
    path_params = event.get("pathParameters") or {}
    task_id = path_params.get("id")

    try:
        if method == "POST":
            return create_task(event)
        if method == "GET" and task_id:
            return get_task(task_id)
        if method == "GET":
            return list_tasks()
        if method == "PUT" and task_id:
            return update_task(task_id, event)
        if method == "DELETE" and task_id:
            return delete_task(task_id)
        return respond(400, {"error": "Unsupported route"})
    except Exception as exc:
        return respond(500, {"error": str(exc)})


def create_task(event):
    body = json.loads(event["body"] or "{}")
    item = {
        "id": str(uuid.uuid4()),
        "title": body.get("title", "Untitled task"),
        "done": False,
    }
    table.put_item(Item=item)
    return respond(201, item)


def list_tasks():
    result = table.scan()
    return respond(200, result.get("Items", []))


def get_task(task_id):
    result = table.get_item(Key={"id": task_id})
    item = result.get("Item")
    if not item:
        return respond(404, {"error": "Task not found"})
    return respond(200, item)


def update_task(task_id, event):
    body = json.loads(event["body"] or "{}")
    table.update_item(
        Key={"id": task_id},
        UpdateExpression="SET title = :t, done = :d",
        ExpressionAttributeValues={
            ":t": body.get("title", "Untitled task"),
            ":d": body.get("done", False),
        },
    )
    return respond(200, {"id": task_id, "updated": True})


def delete_task(task_id):
    table.delete_item(Key={"id": task_id})
    return respond(204, {})


def respond(status_code, body):
    return {
        "statusCode": status_code,
        "headers": {"Content-Type": "application/json"},
        "body": json.dumps(body),
    }

Notice that respond() always returns a dictionary with statusCode, headers, and a stringified body. That exact shape is not optional. API Gateway’s proxy integration expects it, and returning anything else is the single most common cause of a 502 error, covered in the troubleshooting section further down.

Step 4: Package and Deploy the Function via AWS CLI

Zip the function from inside its own directory, so lambda_function.py sits at the root of the archive rather than inside a subfolder, then create the function with the role ARN from Step 2.

$ zip function.zip lambda_function.py
  adding: lambda_function.py (deflated 61%)

$ aws lambda create-function \
  --function-name task-manager-api \
  --runtime python3.13 \
  --handler lambda_function.handler \
  --role arn:aws:iam::123456789012:role/task-manager-lambda-role \
  --zip-file fileb://function.zip \
  --timeout 10 \
  --memory-size 256 \
  --environment "Variables={TABLE_NAME=tasks}"

The TABLE_NAME environment variable matters more than it looks. Hardcoding the table name inside the Python file instead is a common shortcut that breaks the moment you deploy a second stage or a second environment, since both would fight over the same table.

Step 5: Test and Invoke Your Function

Before wiring up API Gateway, confirm the function itself works by invoking it directly with a payload shaped like what API Gateway will eventually send.

$ aws lambda invoke \
  --function-name task-manager-api \
  --cli-binary-format raw-in-base64-out \
  --payload '{"httpMethod":"POST","body":"{\"title\":\"Ship the API\"}"}' \
  response.json

$ cat response.json
{"statusCode": 201, "headers": {"Content-Type": "application/json"}, "body": "{\"id\": \"3f2a9c4e-91b7-4c3a-8f2d-6a1e0c9b5d7f\", \"title\": \"Ship the API\", \"done\": false}"}

A 201 status code with an item back means the function, the IAM role, and the DynamoDB table (created in Step 8, so invoke this again after that step if you are following in order) are all wired correctly at the code level, before API Gateway enters the picture at all.

Step 6: Create a REST API With Amazon API Gateway

Create the REST API and a /tasks resource under its root path. API Gateway needs the root resource ID before it can attach anything else.

$ API_ID=$(aws apigateway create-rest-api --name task-manager-api --query 'id' --output text)

$ ROOT_ID=$(aws apigateway get-resources --rest-api-id $API_ID --query 'items[0].id' --output text)

$ TASKS_ID=$(aws apigateway create-resource \
  --rest-api-id $API_ID \
  --parent-id $ROOT_ID \
  --path-part tasks \
  --query 'id' --output text)

Repeat create-resource once more with --path-part {id} and --parent-id $TASKS_ID to add the /tasks/{id} path the single-item routes need.

Step 7: Connect API Gateway to Lambda With Proxy Integration

With the resources in place, attach an ANY method to each one and point it at Lambda using AWS_PROXY integration, which forwards the entire request instead of requiring a manual mapping template.

$ aws apigateway put-method \
  --rest-api-id $API_ID --resource-id $TASKS_ID \
  --http-method ANY --authorization-type NONE

$ aws apigateway put-integration \
  --rest-api-id $API_ID \
  --resource-id $TASKS_ID \
  --http-method ANY \
  --type AWS_PROXY \
  --integration-http-method POST \
  --uri arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:123456789012:function:task-manager-api/invocations

$ aws lambda add-permission \
  --function-name task-manager-api \
  --statement-id apigateway-invoke \
  --action lambda:InvokeFunction \
  --principal apigateway.amazonaws.com \
  --source-arn "arn:aws:execute-api:us-east-1:123456789012:$API_ID/*/*"

$ aws apigateway create-deployment --rest-api-id $API_ID --stage-name prod

That last command is easy to forget and the most common reason a change appears to do nothing. API Gateway does not auto-deploy. Every route or integration change sits invisible until you run create-deployment again.

Step 8: Add a Database Layer With DynamoDB

Create the table the function already expects. On-demand billing mode means you pay per request instead of provisioning throughput you have to guess at in advance, which fits a project with unpredictable early traffic.

$ aws dynamodb create-table \
  --table-name tasks \
  --attribute-definitions AttributeName=id,AttributeType=S \
  --key-schema AttributeName=id,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST

If your project needs relational joins, multi-table transactions, or SQL, DynamoDB is the wrong tool and Amazon Aurora or RDS is worth a look instead. For a flat task list keyed by ID, a single DynamoDB table with on-demand pricing is simpler to operate and cheaper at low volume.

Step 9: Secure the API With Throttling and an Authorizer

An API with no rate limiting is an open invitation for a traffic spike, accidental or otherwise, to run up your bill or exhaust DynamoDB’s on-demand scaling curve. Create a usage plan and require an API key on every route.

$ aws apigateway create-usage-plan \
  --name task-manager-basic \
  --throttle burstLimit=20,rateLimit=10 \
  --quota limit=10000,period=MONTH

For anything beyond a personal project, swap the API-key approach for a proper Lambda authorizer or Amazon Cognito user pool authorizer, so requests carry a verifiable identity rather than a shared secret that anyone with the key can reuse.

Step 10: Deploy Everything as Code With AWS SAM

Running each CLI command by hand is fine for learning how the pieces connect, but it does not scale to a second environment or a teammate who needs to reproduce your stack. AWS SAM turns the entire setup, function, API, table, and permissions, into one template you can redeploy on demand. If you have used Terraform for AWS infrastructure before, SAM will feel familiar, just narrower in scope and purpose-built for serverless.

# template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Task Manager serverless API

Resources:
  TasksTable:
    Type: AWS::Serverless::SimpleTable
    Properties:
      TableName: tasks
      PrimaryKey:
        Name: id
        Type: String

  TaskManagerFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: lambda_function.handler
      Runtime: python3.13
      MemorySize: 256
      Timeout: 10
      Environment:
        Variables:
          TABLE_NAME: tasks
      Policies:
        - DynamoDBCrudPolicy:
            TableName: tasks
      Events:
        TasksApi:
          Type: Api
          Properties:
            Path: /tasks
            Method: ANY
        TaskByIdApi:
          Type: Api
          Properties:
            Path: /tasks/{id}
            Method: ANY

Outputs:
  ApiUrl:
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/tasks"
$ sam build
$ sam deploy --guided

sam deploy --guided walks through stack naming and confirmation prompts once, then saves the answers to samconfig.toml so every later deploy is a plain sam deploy. The DynamoDBCrudPolicy helper generates the same least-privilege permissions you wrote by hand in Step 2, scoped automatically to the table SAM creates.

Step 11: Add Logging, Metrics, and X-Ray Tracing

Every Lambda invocation already writes to CloudWatch Logs by default through the AWSLambdaBasicExecutionRole policy attached in Step 2. Turn on active tracing to see exactly where time goes across Lambda, DynamoDB, and API Gateway in a single request.

$ aws lambda update-function-configuration \
  --function-name task-manager-api \
  --tracing-config Mode=Active

To find failures fast once the API is live, a CloudWatch Logs Insights query beats scrolling through raw logs.

fields @timestamp, @message
| filter @message like /ERROR/
| sort @timestamp desc
| limit 20

Step 12: Cut Cold Starts and Right-Size Memory

A 256 MB Python function like this one typically cold-starts in well under a second, but if your API sits behind a mobile app or a latency-sensitive frontend, even that can be worth trimming. Provisioned concurrency keeps a set number of execution environments warm at all times.

$ aws lambda put-provisioned-concurrency-config \
  --function-name task-manager-api \
  --qualifier prod \
  --provisioned-concurrent-executions 2

That command creates a standing cost even when nobody is calling the API, so treat it as a production decision, not a default. Memory tuning is usually the higher-leverage fix, and the pricing section below shows why: Lambda bills GB-seconds, so a function that finishes faster at a higher memory setting can end up cheaper than a slow, skinny one.

Your Complete Working Project

Once every step above is done, the project folder looks like this, and any of the three deployment paths (manual CLI, SAM, or a CI pipeline built on either) can redeploy it from scratch.

task-manager-api/
├── lambda_function.py
├── requirements.txt
├── template.yaml
├── trust-policy.json
├── dynamodb-policy.json
├── events/
│   └── create-task.json
└── README.md

Test the live, deployed API the same way an actual client would, with plain HTTPS calls against the stage URL API Gateway generated in Step 7 or the ApiUrl output SAM printed in Step 10.

$ curl -X POST https://abc123xyz.execute-api.us-east-1.amazonaws.com/prod/tasks \
  -H "Content-Type: application/json" \
  -d '{"title":"Write the tutorial"}'

{"id":"7f3e1a2b-9c4d-4e5f-8a1b-2c3d4e5f6a7b","title":"Write the tutorial","done":false}

$ curl https://abc123xyz.execute-api.us-east-1.amazonaws.com/prod/tasks

[{"id":"7f3e1a2b-9c4d-4e5f-8a1b-2c3d4e5f6a7b","title":"Write the tutorial","done":false}]

A 201 on the first call and your new task echoed back in the list on the second call means every layer, IAM, Lambda, API Gateway, and DynamoDB, is correctly wired end to end.

AWS Lambda, API Gateway, and DynamoDB Pricing in 2026

Serverless pricing is granular by design, and the Task Manager API from this tutorial costs close to nothing at low traffic because of how generous the combined free tiers are. The figures below come directly from AWS’s published pricing pages.

ServiceMonthly Free TierPay-as-You-Go Rate
Lambda requests1,000,000 requests$0.20 per 1 million requests
Lambda compute400,000 GB-seconds$0.0000166667 per GB-second
Lambda Provisioned ConcurrencyNone$0.0000041667 per GB-second, whether invoked or not
Lambda durable functionsIncluded above$8.00 per million operations
API Gateway REST APIIncluded in AWS Free Tier for new accounts$3.50 per million calls (first tier)
API Gateway HTTP APIIncluded in AWS Free Tier for new accounts$1.00 per million calls (first tier)
DynamoDB writes (on-demand)25 GB storage$0.625 per million write request units
DynamoDB reads (on-demand)Included above$0.125 per million read request units

At 100,000 requests a month, a workload most side projects never reach, the Task Manager API stays entirely inside the free tier on Lambda and DynamoDB, and costs roughly $0.35 on API Gateway REST API calls alone once you clear the free allotment. Switching to an HTTP API instead of a REST API cuts that per-call rate by more than 70%, at the cost of the usage plans and API keys Step 9 depends on. Full details are on AWS’s Lambda pricing page, API Gateway pricing page, and DynamoDB on-demand pricing page.

Common Pitfalls When Building Serverless APIs

Most Lambda API problems trace back to one of these seven mistakes, all of them easy to make once and expensive to debug later.

  • Hardcoding the table name. Reading it from an environment variable, as this tutorial does, is what lets you run a second stage without the two environments colliding.
  • Attaching AdministratorAccess “just to get it working.” That shortcut in Step 2 turns into a security incident the day the function is compromised. Scope the role to exactly the actions it calls.
  • Forgetting to redeploy the API Gateway stage. Route and integration changes sit invisible until you run create-deployment again, covered in Step 7.
  • Returning a raw dictionary instead of the proxy-integration shape. Skipping statusCode, headers, and a stringified body turns every response into a 502.
  • Skipping CORS headers and then debugging a phantom browser failure that is actually a preflight rejection, not a backend bug at all.
  • Setting memory too low to save pennies. Lambda bills GB-seconds, so a slow function at low memory frequently costs more than a fast one at higher memory.
  • Skipping throttling entirely. Without the usage plan from Step 9, a traffic spike or a retry loop in a buggy client can scale Lambda faster than DynamoDB’s on-demand mode can absorb it.

Troubleshooting AWS Lambda and API Gateway Errors

These ten errors account for nearly every support thread about a Lambda-backed API. Match the message, then apply the fix.

Error or SymptomLikely CauseFix
HTTP 502, “Internal server error”Lambda returned something that isn’t valid proxy-integration JSONWrap every response in a helper like respond() with statusCode, headers, and a stringified body
HTTP 403 ForbiddenMissing API key on a route protected by a usage plan, or a resource policy mismatchSend the key in the x-api-key header and confirm the usage plan is linked to the API stage
AccessDeniedException on dynamodb:PutItemIAM role is missing that specific DynamoDB actionAdd the action to the inline policy created in Step 2
“Task timed out after 10.00 seconds”Function timeout too low for a cold start plus a DynamoDB callRaise Timeout in template.yaml, or with update-function-configuration
“Unable to import module ‘lambda_function'”The zip file was created with the code inside a subfolderRezip from inside the project directory so lambda_function.py sits at the archive root
“No ‘Access-Control-Allow-Origin’ header present”CORS isn’t enabled on the API Gateway resourceEnable CORS on the resource and redeploy the stage
Code changes don’t appear when calling the APIForgot to redeploy the API Gateway stage after a route changeRun create-deployment again. Lambda code updates are instant, but stages are not
ProvisionedThroughputExceededExceptionA traffic burst outran DynamoDB’s on-demand scaling curveConfirm the table is in PAY_PER_REQUEST mode. For extreme bursts, warm the table with light traffic first
Function passes in the console test but fails through the live APIConsole test events don’t match the shape API Gateway actually sendsTest with a saved event file that mirrors a real API Gateway payload, like events/create-task.json
{“message”:”Missing Authentication Token”}Requested a path, method, or stage that doesn’t exist on the deploymentDouble-check the exact route and stage prefix in the URL, including /prod

Advanced Tips for Production-Ready Lambda APIs

The steps above get a working API deployed. Getting one ready for real traffic takes a few more decisions.

Provisioned Concurrency, SnapStart, and Managed Instances

Three different AWS features solve cold starts, and they are not interchangeable. Provisioned concurrency, used in Step 12, keeps a fixed number of environments warm at $0.0000041667 per GB-second whether or not they are invoked. SnapStart snapshots an already-initialized environment and restores from it, and now extends beyond its original Java-only scope to Python and .NET, cutting cold starts without a standing cost. Lambda Managed Instances, new in 2026, target a different problem entirely: steady, memory-heavy workloads that need up to 32 GB, well past the standard 10,240 MB ceiling, plus scheduled scaling and automatic tag propagation for fleets of functions.

For the Task Manager API in this tutorial, none of the three are necessary at launch. Add provisioned concurrency only after real traffic data shows cold starts are actually a user-facing problem, not a theoretical one.

A few other decisions separate a demo from something you would put in front of paying users. Adopt AWS Lambda Powertools for structured logging, tracing, and custom metrics instead of scattered print statements. Use a Lambda alias with weighted routing to shift a small percentage of traffic to a new version before a full rollout, so a bad deploy affects a fraction of requests instead of all of them. If your dependencies push the 50 MB zipped deployment package limit, package the function as a container image instead, which supports up to 10 GB. And if you later add an endpoint that runs AI-generated or user-submitted code, look at Lambda MicroVMs, the isolated, stateful execution environment AWS introduced in 2026 specifically for that case, with sessions that persist for up to 8 hours.

AWS Lambda vs Azure Functions vs Cloudflare Workers vs Cloud Run

Lambda is not the only way to run this pattern. The table below compares what each platform actually publishes for its free tier and pricing structure, useful if you are choosing a platform rather than assuming AWS by default.

PlatformMonthly Free TierPaid Rate
AWS Lambda1,000,000 requests + 400,000 GB-seconds$0.20 per 1M requests + $0.0000166667 per GB-second
Azure Functions (Consumption)1,000,000 requests + 400,000 GB-secondsPay-as-you-go, rate varies by region
Cloudflare Workers100,000 requests/day (Free plan)Paid plan from $5/month: 10M requests + 30M CPU-ms included, then $0.30 per additional million requests
Google Cloud Run2,000,000 requests + 180,000 vCPU-seconds + 360,000 GiB-secondsPay-as-you-go, rate varies by region

The free-tier math is closer than most people expect. Azure’s Consumption plan publishes the same 1 million requests and 400,000 GB-seconds Lambda offers, almost figure for figure. Cloudflare Workers runs on V8 isolates rather than full execution environments, which avoids traditional cold starts but caps free CPU time at 10 milliseconds per invocation. Cloud Run bills by container instance rather than per function, which suits a service with several routes better than five separate deployables. For a deeper head-to-head on the two most-compared options, see Cloudflare Workers vs Lambda.

Frequently Asked Questions

What is the difference between AWS Lambda and a traditional server?

A traditional server runs continuously whether or not it is handling requests, and you pay for that uptime. An AWS Lambda function only runs while it is processing an event, then AWS shuts the execution environment down. You pay per request and per GB-second of actual compute, not for idle capacity, which is why a low-traffic API like the one in this tutorial can run almost entirely inside the free tier.

How much does a small AWS Lambda API cost per month?

For the Task Manager API built in this tutorial, likely nothing at low volume. AWS’s free tier covers 1 million Lambda requests, 400,000 GB-seconds of compute, and 25 GB of DynamoDB storage every month. The first cost most small projects hit is API Gateway’s $3.50 per million REST API calls once free-tier request volume is used up, according to AWS’s published pricing.

What programming languages does AWS Lambda support in 2026?

Lambda’s managed runtimes include Python (up to 3.14), Node.js (up to 24.x), Java, Go, Ruby, and .NET, which added .NET 10 support as both a managed runtime and a container base image in January 2026, per AWS’s own weekly roundup. Any language that can run in a container also works through Lambda’s container-image deployment option.

What is the maximum execution time for a Lambda function?

15 minutes per invocation. If a workload regularly needs longer than that, it is a signal to break the job into smaller Lambda invocations, hand it to Step Functions for orchestration, or move it to a container-based service like Fargate instead of forcing it into Lambda’s execution model.

Do I need API Gateway to use Lambda?

No. Lambda function URLs give a function its own HTTPS endpoint without API Gateway at all, and services like S3 or EventBridge can invoke Lambda directly with no API layer whatsoever. API Gateway earns its place when you need usage plans, API keys, request validation, or multiple routes managed under one stage, all of which the Task Manager API in this tutorial uses.

Is DynamoDB required, or can I use RDS instead?

DynamoDB is not mandatory, just the simplest fit for a flat, key-value task list. Lambda can also connect to Amazon Aurora or RDS through the RDS Data API or a connection pooler like RDS Proxy, worth considering if your data model needs relational joins, foreign keys, or SQL that DynamoDB’s item-based model does not support well.

How do I stop my AWS Lambda function from timing out on cold starts?

First confirm the timeout in Step 4 is generous enough to cover a cold start plus a DynamoDB round trip, usually a few seconds is plenty for a function this size. If cold starts are still a measurable problem under real traffic, provisioned concurrency or SnapStart, both covered in the advanced tips section, address it directly, at the cost of a standing charge or a more involved setup.

How do I secure a Lambda-backed API in production?

Layer it: a least-privilege IAM role as built in Step 2, a usage plan with throttling as built in Step 9, and a real authorizer, either a custom Lambda authorizer or an Amazon Cognito user pool, in place of a shared API key for anything beyond a personal project. Add AWS WAF in front of API Gateway if the API is public-facing and expects meaningful traffic.

Related Coverage

Marcus Chen

Marcus Chen

Gaming & Consumer Tech Editor

Marcus Chen is a senior editor at Tech Insider, where he leads coverage of the US online gaming market, including sweepstakes and social casinos, alongside consumer technology. He evaluates operators on their published terms, licensing and RNG certifications, stated redemption policies, and corroborating independent reporting, and writes plainly about what the evidence supports. Tech Insider does not run first-party money tests and does not gamble with reader funds. Marcus has reported on the technology and online-gaming industries for more than a decade.

View all articles