Production Engineering/
Lesson

"ServerlessWhat is serverless?A hosting model where individual functions run on demand and the platform handles all server management, scaling, and uptime for you." is a bit of a marketing term, there are absolutely servers involved. What it really means is that you don't manage any servers. You write a function, deploy it, and the cloud providerWhat is provider?A wrapper component that makes data available to all components nested inside it without passing props manually. handles everything else: provisioning, scaling, load balancing, patching, and availability. You focus on the code.

How it compares to traditional hosting

With a traditional server, you rent compute that runs 24/7. With serverlessWhat is serverless?A hosting model where individual functions run on demand and the platform handles all server management, scaling, and uptime for you., your code runs only when triggered and scales automatically from zero to tens of thousands of concurrent executions.

Traditional server:
  - Rent a VPS ($20-100/month)
  - Pay whether or not you get requests
  - You manage scaling, updates, uptime

Serverless:
  - Write a function
  - Deploy in seconds
  - Runs on demand, auto-scales
  - Pay only for execution time
02

Writing serverlessWhat is serverless?A hosting model where individual functions run on demand and the platform handles all server management, scaling, and uptime for you. functions

The shape of a serverless function is platform-specific, but the concept is the same: receive an event, return a response.

// AWS Lambda
exports.handler = async (event) => {
  const name = event.name || 'World';
  return {
    statusCode: 200,
    body: JSON.stringify({ message: `Hello ${name}!` })
  };
};

// Vercel / Next.js API route
export default async function handler(req, res) {
  res.status(200).json({ message: 'Hello!' });
}

// Cloudflare Worker
export default {
  async fetch(request) {
    return new Response('Hello from the edge!');
  }
};
03

What serverlessWhat is serverless?A hosting model where individual functions run on demand and the platform handles all server management, scaling, and uptime for you. is great at

Serverless shines when work is event-driven and execution time is short and bounded.

Use caseTriggerWhy it works
API endpointsHTTP requestAuto-scales to any traffic level
Image resizingFile uploadRuns once per upload, then stops
WebhooksThird-party eventInfrequent, short-lived
Scheduled jobsCron timerNo server needed between runs
Queue processingMessage queueScales with queue depth
// Image resizing triggered by S3 upload
exports.handler = async (event) => {
  const bucket = event.Records[0].s3.bucket.name;
  const key = event.Records[0].s3.object.key;
  const image = await s3.getObject({ Bucket: bucket, Key: key }).promise();
  const resized = await sharp(image.Body).resize(800, 600).toBuffer();
  await s3.putObject({ Bucket: bucket, Key: `thumbnails/${key}`, Body: resized }).promise();
};
04

Cold starts

The biggest practical downside of serverlessWhat is serverless?A hosting model where individual functions run on demand and the platform handles all server management, scaling, and uptime for you. is the cold startWhat is cold start?The delay that occurs when a serverless function runs for the first time after being idle. The cloud provider needs to spin up a new container, which adds latency.. When a function hasn't been used recently, the cloud providerWhat is provider?A wrapper component that makes data available to all components nested inside it without passing props manually. needs to spin up a new containerWhat is container?A lightweight, portable package that bundles your application code with all its dependencies so it runs identically on any machine. to run it. That initialization adds latencyWhat is latency?The time delay between sending a request and receiving the first byte of the response, usually measured in milliseconds., typically 100ms to 1000ms depending on the platform and your function's dependencies.

For user-facing APIs, this can be noticeable. Solutions include:

  • Provisioned concurrencyWhat is concurrency?The ability of a program to handle multiple tasks at the same time, like serving thousands of users without slowing down. (AWS), keeps instances warm, but costs money even when idle
  • Periodic pings: a scheduled function that calls your function every few minutes to keep it warm
  • Cloudflare Workers: runs on V8What is v8?Google's JavaScript engine that compiles JavaScript to native machine code - it powers both Chrome and Node.js. isolates instead of containers, near-zero cold starts
Cold starts hurt most for functions with heavy dependencies. Keep your serverless functions small and minimize npm imports to reduce initialization time.
05

Pricing model

Traditional server:
  $50/month regardless of traffic

AWS Lambda pricing:
  $0.20 per 1 million requests
  $0.00001667 per GB-second of compute

Example: 100,000 requests/month at 100ms each
  Cost: ~$0.20/month

AWS Lambda's free tier includes 1 million requests and 400,000 GB-seconds of compute per month. For small projects, serverlessWhat is serverless?A hosting model where individual functions run on demand and the platform handles all server management, scaling, and uptime for you. is effectively free.

The cost equation flips under constant high load. If your function runs millions of times a day every day, a dedicated server is often cheaper.

06

When serverlessWhat is serverless?A hosting model where individual functions run on demand and the platform handles all server management, scaling, and uptime for you. fits and when it doesn't

Good fitPoor fit
Variable or unpredictable trafficConstant high-throughput traffic
Event-driven workflowsLong-running jobs (> 15 minutes)
Webhooks and integrationsStateful websocket connections
Scheduled background tasksWhen you need full server control
Low-to-medium traffic APIsLatency-sensitive with zero cold-start tolerance
javascript
// Serverless Examples

// 1. AWS Lambda, API Endpoint
exports.handler = async (event) => {
  const { httpMethod, path, body } = event;

  // Parse request
  const data = JSON.parse(body || '{}');

  // Handle different routes
  if (httpMethod === 'GET' && path === '/users') {
    const users = await db.users.findAll();
    return {
      statusCode: 200,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(users)
    };
  }

  if (httpMethod === 'POST' && path === '/users') {
    const user = await db.users.create(data);
    return {
      statusCode: 201,
      body: JSON.stringify(user)
    };
  }

  return {
    statusCode: 404,
    body: JSON.stringify({ error: 'Not found' })
  };
};

// 2. Vercel Serverless Function
// pages/api/hello.js
export default async function handler(req, res) {
  if (req.method === 'GET') {
    res.status(200).json({ message: 'Hello!' });
  } else {
    res.status(405).json({ error: 'Method not allowed' });
  }
}

// 3. Image Processing (S3 Trigger)
exports.handler = async (event) => {
  const bucket = event.Records[0].s3.bucket.name;
  const key = event.Records[0].s3.object.key;

  // Download image from S3
  const image = await s3.getObject({ Bucket: bucket, Key: key }).promise();

  // Resize
  const resized = await sharp(image.Body)
    .resize(800, 600)
    .toBuffer();

  // Upload thumbnail
  await s3.putObject({
    Bucket: bucket,
    Key: `thumbnails/${key}`,
    Body: resized
  }).promise();

  console.log(`Processed ${key}`);
};

// 4. Scheduled Task (Cron)
exports.handler = async () => {
  // Runs every day at 9 AM
  const users = await db.users.findInactive();

  for (const user of users) {
    await sendEmail(user.email, 'We miss you!');
  }

  return {
    statusCode: 200,
    body: `Sent ${users.length} emails`
  };
};

// 5. Webhook Handler
exports.handler = async (event) => {
  const signature = event.headers['stripe-signature'];

  // Verify webhook
  const payload = JSON.parse(event.body);
  const valid = verifySignature(payload, signature);

  if (!valid) {
    return { statusCode: 401, body: 'Invalid signature' };
  }

  // Process payment
  if (payload.type === 'payment_intent.succeeded') {
    await processPayment(payload.data.object);
  }

  return { statusCode: 200, body: 'OK' };
};