serverless-edge-computing-cloud-infrastructure

Serverless and Edge Computing with Node.js: Deploy Faster, Cheaper, and Closer to Your Users

Serverless và Edge Computing đang thay đổi cách deploy ứng dụng Node.js. Từ AWS Lambda đến Cloudflare Workers — học cách xây dựng apps có latency cực thấp, auto-scale, và chỉ trả tiền khi có người dùng.

Written by admin
April 24, 2026 10 min read 2,610 views
Cloud computing data center technology representing serverless and edge infrastructure

According to the Stack Overflow Developer Survey 2025, 48.7% of developers worldwide use Node.js — making it the most widely used runtime for a sixth consecutive year. But the way Node.js applications are deployed is undergoing a quiet revolution. Traditional VPS and dedicated server deployments are giving way to serverless functions and edge computing, where your code runs not in one data center but at 300+ locations worldwide, milliseconds from wherever your users are.

63% of developers now deploy at least part of their application through serverless infrastructure. The reasons are practical: no servers to provision, automatic scaling to zero, and a billing model where you pay only for actual execution time. No traffic means no cost. An API that gets 10,000 requests a month costs fractions of a cent to run.

This guide covers both serverless and edge computing from a Node.js perspective: what each model actually means, hands-on implementation with AWS Lambda and Cloudflare Workers, cold start optimization strategies, when to use each approach, and the honest cost comparison that will help you make the right architectural decision.

Two Models, One Goal: Reducing Infrastructure Overhead

Serverless Computing

The core promise of serverless is simple: you write the function, the cloud provider handles everything else. Server provisioning, OS patching, runtime upgrades, horizontal scaling, load balancing, health checks — all of it is abstracted away. You deploy a function; the platform ensures it runs when invoked.

The billing model follows from this: you pay only when your function actually executes. Idle time costs nothing. A REST API that receives 50,000 requests per month and averages 100ms per request will run for about 83 minutes of total compute time — and that’s all you pay for. Compare this to a VPS that bills 24/7 regardless of whether a single request arrived.

Edge Computing

Edge computing takes the serverless model and distributes it globally. Instead of your function running in a single region — say, us-east-1 in Virginia — it runs at the edge node nearest to the person making the request. A user in Vietnam triggers execution in Singapore. A user in France triggers execution in Paris. A user in Brazil triggers execution in São Paulo.

The latency impact is dramatic. A typical round-trip from Vietnam to a US-based server takes 200–250ms before your function even starts executing. From Vietnam to a Singapore edge node, that drops to under 20ms. For applications where perceived responsiveness matters — authentication flows, personalization, API gateways, A/B testing logic — the difference is immediately noticeable to users.

Choosing Your Platform

The major serverless and edge platforms each have distinct strengths:

  • AWS Lambda — The most mature serverless platform. Widest ecosystem integration (API Gateway, DynamoDB, S3, SQS, EventBridge). Cold starts of 100–300ms for Node.js. Best choice for complex backend workflows with multiple AWS service dependencies.
  • Cloudflare Workers — Runs at 300+ edge locations globally. Sub-1ms cold starts (uses V8 isolates instead of containers). 100,000 requests per day on the free tier. Best choice for latency-sensitive APIs, middleware, and globally distributed workloads.
  • Vercel Functions — Optimized for Next.js deployments with native integration into the Vercel platform. Excellent developer experience. Best choice for full-stack JavaScript applications already using Next.js.
  • Netlify Functions — Built on AWS Lambda with a simplified deployment model. Best choice for JAMstack sites and simple API backends alongside static sites.

AWS Lambda: Hands-On Implementation

Lambda functions for Node.js 24 use ES Module syntax with .mjs extensions or "type": "module" in package.json. Here’s a complete API handler covering two common endpoints:

// handler.mjs — ES Module for Node.js 24
export const handler = async (event) => {
  const { httpMethod, path, queryStringParameters, body } = event;

  if (httpMethod === "GET" && path === "/api/articles") {
    const page = parseInt(queryStringParameters?.page) || 1;
    const articles = await fetchArticles(page);
    return {
      statusCode: 200,
      headers: {
        "Content-Type": "application/json",
        "Cache-Control": "public, max-age=60",
      },
      body: JSON.stringify({ data: articles, page, total: articles.length }),
    };
  }

  if (httpMethod === "POST" && path === "/api/contact") {
    const data = JSON.parse(body);
    await sendEmail(data);
    return { statusCode: 200, body: JSON.stringify({ message: "Sent successfully!" }) };
  }

  return { statusCode: 404, body: "Not Found" };
};

The corresponding Serverless Framework configuration deploys this function to AWS with Node.js 24 runtime in the Southeast Asia region, with a 256MB memory allocation and a 10-second timeout:

service: techher-api
frameworkVersion: "4"

provider:
  name: aws
  runtime: nodejs24.x
  region: ap-southeast-1
  memorySize: 256
  timeout: 10

functions:
  api:
    handler: handler.handler
    events:
      - httpApi:
          path: /api/{proxy+}
          method: ANY
npm install -g serverless
serverless deploy

One deployment command handles packaging your code, uploading it to S3, creating the Lambda function, configuring API Gateway, and wiring up IAM permissions. The entire stack is defined as code and reproducible across environments.

Cloudflare Workers: Edge Computing in Practice

Cloudflare Workers use a fundamentally different execution model than Lambda. Instead of containers (which have startup overhead), Workers use V8 isolates — lightweight execution contexts that start in under a millisecond. This eliminates cold starts as a practical concern.

Workers also have direct access to Cloudflare’s request metadata: the user’s country, city, and the edge location processing the request. This enables geolocation-aware responses without any external API calls:

// worker.js — Cloudflare Worker
export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    if (url.pathname === "/api/hello") {
      const country = request.cf?.country || "Unknown";
      const city = request.cf?.city || "Unknown";
      const colo = request.cf?.colo;

      return new Response(JSON.stringify({
        message: `Hello from ${city}, ${country}!`,
        processedAt: colo,
        latency: "< 20ms",
        timestamp: new Date().toISOString(),
      }), {
        headers: { "Content-Type": "application/json" },
      });
    }

    if (url.pathname === "/api/visits") {
      const count = parseInt(await env.VISITS.get("count") || "0") + 1;
      await env.VISITS.put("count", count.toString());
      return new Response(JSON.stringify({ visits: count }), {
        headers: { "Content-Type": "application/json" },
      });
    }

    return new Response("Not Found", { status: 404 });
  },
};

The /api/visits endpoint demonstrates Cloudflare KV — a globally distributed key-value store that replicates across edge locations. Workers are stateless themselves, but KV provides the persistent storage layer they need for use cases like visit counting, feature flags, and user session data.

Solving Cold Starts: Three Proven Strategies

Cold starts — the latency penalty when a serverless function initializes from scratch — are the most commonly cited concern about serverless architectures. Here are three approaches that address them at different levels:

Strategy 1: Lazy Initialization with Module-Level Caching

Lambda execution environments are reused across multiple invocations. Any initialization performed outside the handler function persists between warm invocations. The pattern is to lazily initialize expensive resources — database connections, HTTP clients, loaded ML models — on first invocation and cache them at module scope:

// Cold start optimization — lazy database connection caching
let dbConnection;

async function getDB() {
  if (!dbConnection) {
    const { Client } = await import("pg");
    dbConnection = new Client(process.env.DATABASE_URL);
    await dbConnection.connect();
  }
  return dbConnection;
}

// NestJS Lambda adapter with server caching
import { NestFactory } from "@nestjs/core";
import { ExpressAdapter } from "@nestjs/platform-express";
import serverlessExpress from "@codegenie/serverless-express";
import express from "express";
import { AppModule } from "./app.module";

let cachedServer;

async function bootstrap() {
  if (!cachedServer) {
    const app = express();
    const nestApp = await NestFactory.create(AppModule, new ExpressAdapter(app));
    nestApp.enableCors();
    await nestApp.init();
    cachedServer = serverlessExpress({ app });
  }
  return cachedServer;
}

export const handler = async (event, context) => {
  const server = await bootstrap();
  return server(event, context);
};

The NestJS adapter pattern shown above is particularly important. NestJS applications have significant startup overhead — dependency injection resolution, module initialization, middleware registration. By caching cachedServer at module scope, you pay this cost once on the first cold start and amortize it across all subsequent warm invocations.

Strategy 2: Reduce Bundle Size

Lambda cold start time scales with the size of your deployment package. The most impactful optimization is using modular imports from the AWS SDK rather than importing the entire library. Instead of import AWS from 'aws-sdk', import only the specific client you need: import { DynamoDBClient } from "@aws-sdk/client-dynamodb". This alone can reduce bundle sizes by 60–80% for AWS-heavy applications.

Strategy 3: Provisioned Concurrency

For latency-critical endpoints where even a 120ms cold start is unacceptable, AWS offers Provisioned Concurrency — keeping a specified number of execution environments permanently warm and ready to respond. Five provisioned instances cost approximately $15/month and guarantee sub-10ms response times for the first five concurrent requests, regardless of traffic patterns.

Cold Start Benchmarks by Runtime

Cold start performance varies significantly by language runtime. For teams with flexibility in their technology choices, this comparison is relevant:

  • Go: 90ms
  • Node.js 24: 120ms
  • Python 3.12: 180ms
  • .NET 8: 250ms
  • Java 21: 350ms

Go has the fastest cold starts, but Node.js’s 120ms is close — and Node.js brings a far richer ecosystem of libraries, dramatically more developers with relevant experience, and the ability to share code between frontend and backend. For most teams, Node.js represents the best balance of cold start performance, ecosystem depth, and developer experience.

When Serverless Is the Wrong Choice

Serverless is genuinely excellent for many workloads, but it’s not universally appropriate. Be honest about these constraints before committing:

  • WebSocket connections — Serverless functions have execution time limits (30 seconds to 15 minutes depending on platform). Long-lived WebSocket connections that require persistent state over hours don’t fit this model. Use dedicated WebSocket servers or Cloudflare Durable Objects instead.
  • Heavy computation — ML model training, video encoding, large-scale data processing. Serverless functions have strict memory limits and execution time caps. For sustained heavy compute, EC2 or dedicated GPU instances are more appropriate.
  • Consistent ultra-low latency requirements — If 120ms cold start latency is unacceptable for your SLA and Provisioned Concurrency costs are prohibitive, an always-on server process may be more suitable.
  • Very high request volumes — At over 10 million requests per month, the per-invocation pricing of serverless can exceed the flat cost of a comparable VPS. Run the numbers before assuming serverless is cheaper at scale.
  • Shared mutable state — Serverless functions are stateless by design. If your application architecture requires shared in-memory state between requests (not an external database, but actual in-process state), you need a persistent server process.

The Real Cost Comparison

For a typical API workload — 5 million requests per month, averaging 100ms execution time per request, 256MB memory allocation:

  • AWS Lambda: approximately $22/month
  • DigitalOcean VPS (4GB RAM): $24/month

At this scale, the costs are nearly identical. The serverless advantage is that it scales to zero automatically during low-traffic periods, whereas the VPS costs $24/month even during nights and weekends when traffic drops to near-zero.

Under 1 million requests per month, serverless is dramatically cheaper — often near $0 on AWS’s free tier (1 million requests/month included permanently). Over 20 million requests per month with consistent traffic patterns, a VPS becomes meaningfully cheaper. The crossover point depends on your specific execution times and memory requirements, but the general principle holds.

“Serverless is not just a deployment model — it’s a different way of thinking about infrastructure. You don’t manage servers. You manage functions. The cloud handles the rest.” — Werner Vogels, CTO of Amazon

Conclusion

Serverless and edge computing have moved from “interesting architecture pattern” to “default choice for new Node.js APIs.” The reasons are practical and compounding: lower operational overhead, automatic scaling, near-zero idle costs, and for edge deployments, latency that was simply not achievable with centralized server architectures.

For teams starting a new Node.js API or microservice today, the recommended path is clear: begin with Cloudflare Workers if global edge distribution and sub-millisecond cold starts are priorities, or AWS Lambda if deep integration with the AWS ecosystem is required. For Next.js applications, Vercel Functions provide the most frictionless path to production.

The patterns in this guide — ES Module handlers, execution environment caching for NestJS, lazy database initialization, modular SDK imports for bundle reduction — are directly applicable to production deployments today. The cold start benchmarks and cost comparisons give you the data to make architectural decisions with confidence rather than intuition.

The shift to serverless and edge isn’t a trend to evaluate in future planning cycles. It’s the default deployment model for Node.js applications now — and Node.js 24’s performance improvements make it an even more compelling runtime choice for these environments than it has ever been.

Enjoyed this article?

Get weekly insights on Tech, AI & Beauty — straight to your inbox.

Leave a Comment

Your email address will not be published. Required fields are marked *