FroquizFroquiz
HomeQuizzesSenior ChallengeGet CertifiedBlogAbout
Sign InStart Quiz
Sign InStart Quiz
Froquiz

The most comprehensive quiz platform for software engineers. Test yourself with 10000+ questions and advance your career.

LinkedIn

Platform

  • Start Quizzes
  • Topics
  • Blog
  • My Profile
  • Sign In

About

  • About Us
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

Β© 2026 Froquiz. All rights reserved.Built with passion for technology
Blog & Articles

AWS Lambda and Serverless: A Developer's Practical Guide

Learn AWS Lambda and serverless architecture from scratch. Covers function structure, triggers, cold starts, environment variables, layers, error handling, and when to go serverless.

Yusuf SeyitoğluMarch 11, 20260 views10 min read

AWS Lambda and Serverless: A Developer's Practical Guide

Serverless computing fundamentally changes how you think about infrastructure. Instead of managing servers, you deploy functions that run on demand, scale automatically, and charge you only for what you use. AWS Lambda is the leading serverless compute service β€” and understanding it is increasingly expected for any cloud-aware developer.

What Is Serverless?

"Serverless" does not mean no servers β€” it means you do not manage them. The cloud provider handles:

  • Provisioning and scaling infrastructure
  • Patching and maintaining the OS
  • Capacity planning

You just write code. You pay per request and execution duration, not for idle server time.

AWS Lambda Basics

A Lambda function is a piece of code that runs in response to an event. AWS manages the underlying compute.

javascript
// Node.js Lambda handler export const handler = async (event, context) => { console.log("Event:", JSON.stringify(event)); const name = event.queryStringParameters?.name ?? "World"; return { statusCode: 200, headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: `Hello, ${name}!` }), }; };

The handler receives:

  • event β€” the trigger data (HTTP request, S3 event, SQS message, etc.)
  • context β€” runtime info (function name, remaining time, request ID)
  • Returns a response appropriate for the trigger type

Lambda Triggers

Lambda functions respond to dozens of event sources:

TriggerUse case
API Gateway / Function URLHTTP API endpoints
S3Process files on upload
SQSProcess messages from a queue
SNSReact to notifications
DynamoDB StreamsReact to database changes
EventBridgeScheduled tasks (cron jobs)
CognitoUser authentication hooks
CloudFrontEdge computing

HTTP API with API Gateway

yaml
# serverless.yml (Serverless Framework) functions: getUser: handler: src/users.getUser events: - httpApi: path: /users/{id} method: GET createUser: handler: src/users.createUser events: - httpApi: path: /users method: POST

Scheduled function (cron)

yaml
functions: dailyReport: handler: src/reports.generate events: - schedule: cron(0 8 * * ? *) # every day at 8:00 UTC

S3 trigger

javascript
export const handler = async (event) => { for (const record of event.Records) { const bucket = record.s3.bucket.name; const key = record.s3.object.key; console.log(`Processing s3://${bucket}/${key}`); await processUploadedFile(bucket, key); } };

Cold Starts

When a Lambda function has not been invoked recently, AWS needs to initialize a new execution environment. This initialization is called a cold start and adds latency β€” typically 100ms to 1s depending on runtime and function size.

After the first invocation, the environment is reused for subsequent requests (warm start β€” much faster).

Minimizing cold starts

javascript
// Initialize heavy resources outside the handler // They are reused across warm invocations import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; const dynamodb = new DynamoDBClient({ region: "eu-west-1" }); const secretCache = new Map(); export const handler = async (event) => { // dynamodb client is already initialized -- reused const result = await dynamodb.send(...); return result; };

Additional strategies:

  • Keep functions small β€” less code to initialize
  • Use lighter runtimes β€” Node.js and Python cold start faster than Java or .NET
  • Use Provisioned Concurrency to keep environments warm (costs more)
  • Use Lambda SnapStart (Java) to snapshot the initialized environment

Environment Variables and Secrets

yaml
functions: api: handler: src/api.handler environment: NODE_ENV: production DB_HOST: ${ssm:/myapp/db/host} DB_NAME: myapp_prod

For sensitive values, fetch from AWS Secrets Manager at runtime rather than storing in environment variables:

javascript
import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager"; const sm = new SecretsManagerClient({ region: "eu-west-1" }); let cachedSecret; async function getDbPassword() { if (cachedSecret) return cachedSecret; const response = await sm.send(new GetSecretValueCommand({ SecretId: "myapp/db/password", })); cachedSecret = response.SecretString; return cachedSecret; }

Caching the secret in the module scope avoids fetching it on every invocation.

Lambda Layers

Layers are ZIP archives that can be shared across multiple functions β€” great for common dependencies or shared utilities:

yaml
layers: commonDeps: path: layer compatibleRuntimes: - nodejs20.x functions: api: handler: src/api.handler layers: - !Ref CommonDepsLambdaLayer

Layers are mounted at /opt in the execution environment. Use them to:

  • Share large libraries (e.g., Puppeteer, ffmpeg binaries) across functions
  • Reduce deployment package size
  • Update shared code without redeploying every function

Error Handling and Retries

Lambda retries failed invocations differently depending on the trigger:

  • Synchronous invocations (API Gateway) β€” no automatic retry; error returned to caller
  • Asynchronous invocations (S3, SNS) β€” retries up to 2 times with delays
  • Queue-based (SQS) β€” retries until message expires or hits DLQ

Always configure a Dead Letter Queue (DLQ) for async and queue-based invocations:

yaml
functions: processOrder: handler: src/orders.process events: - sqs: arn: !GetAtt OrdersQueue.Arn batchSize: 10 destinations: onFailure: arn:aws:sqs:eu-west-1:123456789:OrdersDLQ
javascript
export const handler = async (event) => { const results = await Promise.allSettled( event.Records.map(record => processRecord(record)) ); // Report partial batch failures (SQS) const failures = results .map((r, i) => r.status === "rejected" ? { itemIdentifier: event.Records[i].messageId } : null) .filter(Boolean); return { batchItemFailures: failures }; // only failed messages return to queue };

IAM Permissions

Lambda functions need an IAM role with permissions for every AWS service they touch:

yaml
provider: iam: role: statements: - Effect: Allow Action: - dynamodb:GetItem - dynamodb:PutItem - dynamodb:UpdateItem Resource: !GetAtt UsersTable.Arn - Effect: Allow Action: - s3:GetObject Resource: arn:aws:s3:::my-bucket/* - Effect: Allow Action: - secretsmanager:GetSecretValue Resource: arn:aws:secretsmanager:eu-west-1:*:secret:myapp/*

Always follow the principle of least privilege β€” grant only the exact permissions needed.

When to Use Serverless

Good fit:

  • Event-driven workloads (file processing, message handling, webhooks)
  • APIs with variable or unpredictable traffic
  • Scheduled jobs and background tasks
  • Microservices with low to moderate request rates
  • Prototypes and MVPs (low upfront cost)

Poor fit:

  • Long-running processes (Lambda max timeout is 15 minutes)
  • Workloads requiring persistent connections (WebSockets need special handling)
  • Very high throughput, low-latency APIs (cold starts add unpredictability)
  • Applications needing more than 10GB RAM or 6 vCPUs
  • Workflows requiring fine-grained OS or runtime control

Practice AWS on Froquiz

Cloud and serverless architecture are tested in backend and DevOps interviews. Explore our AWS and infrastructure quizzes on Froquiz across all difficulty levels.

Summary

  • Lambda runs code in response to events β€” no server management
  • Triggers: API Gateway, S3, SQS, EventBridge (cron), DynamoDB Streams, and more
  • Cold starts add latency on first invocation β€” minimize with small packages and module-level initialization
  • Store secrets in Secrets Manager, fetch and cache at function startup
  • Layers share common dependencies and binaries across functions
  • Always configure DLQs for async and queue-based functions
  • IAM roles follow least privilege β€” grant only what each function needs
  • Serverless shines for event-driven, variable-traffic workloads; not ideal for long-running or high-throughput steady-state work

About Author

Yusuf Seyitoğlu

Author β†’

Other Posts

  • CSS Advanced Techniques: Custom Properties, Container Queries, Grid Masonry and Modern LayoutsMar 12
  • Java Collections Deep Dive: ArrayList, HashMap, TreeMap, LinkedHashMap and When to Use EachMar 12
  • GraphQL Schema Design: Types, Resolvers, Mutations and Best PracticesMar 12
All Blogs