DEV Community

Cover image for 6 AWS Patterns JavaScript Developers Use to Replace an Entire DevOps Team
JSGuruJobs
JSGuruJobs

Posted on

6 AWS Patterns JavaScript Developers Use to Replace an Entire DevOps Team

Most JavaScript developers can build features. Far fewer can ship and operate them in production. The difference between a $120K developer and a $160K developer is usually the ability to deploy, scale, and monitor their own infrastructure.

Here are six AWS patterns modern JavaScript teams use to run production systems without a dedicated DevOps engineer.


Lambda Functions Replace Node Servers

Traditional Node APIs run on a server you maintain. That means patching the OS, scaling instances, and handling downtime.

Before

import express from "express"
import { PrismaClient } from "@prisma/client"

const app = express()
const prisma = new PrismaClient()

app.get("/jobs", async (req, res) => {
  const jobs = await prisma.jobPosting.findMany({
    orderBy: { createdAt: "desc" },
    take: 20
  })

  res.json(jobs)
})

app.listen(3000)
Enter fullscreen mode Exit fullscreen mode

After

import { APIGatewayProxyEvent } from "aws-lambda"
import { PrismaClient } from "@prisma/client"

const prisma = new PrismaClient()

export const handler = async (event: APIGatewayProxyEvent) => {
  const jobs = await prisma.jobPosting.findMany({
    orderBy: { createdAt: "desc" },
    take: 20
  })

  return {
    statusCode: 200,
    body: JSON.stringify(jobs)
  }
}
Enter fullscreen mode Exit fullscreen mode

Lambda removes server management entirely. The function runs only when invoked and scales automatically. A small production API often costs under $10 per month while handling millions of requests.


API Gateway Turns Functions Into Production APIs

Lambda functions do not expose HTTP endpoints on their own. API Gateway handles routing, authentication, rate limits, and CORS.

Before

app.post("/applications", async (req, res) => {
  const application = await prisma.application.create({
    data: req.body
  })

  res.json(application)
})
Enter fullscreen mode Exit fullscreen mode

After

functions:
  createApplication:
    handler: lambda/createApplication.handler
    events:
      - http:
          path: /applications
          method: post
          cors: true
Enter fullscreen mode Exit fullscreen mode

With one configuration block, API Gateway exposes the Lambda function as a public REST endpoint.

You also gain throttling, authentication layers, and request validation without writing middleware.


S3 Replaces File Servers

Many Node applications store uploaded files on the same server running the API. That approach breaks once you scale horizontally.

Before

import fs from "fs"

export async function uploadResume(file, filename) {
  const path = `uploads/${Date.now()}-${filename}`

  fs.writeFileSync(path, file)

  return path
}
Enter fullscreen mode Exit fullscreen mode

After

import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"

const s3 = new S3Client({ region: "us-east-1" })

export async function uploadResume(file: Buffer, filename: string) {
  const key = `resumes/${Date.now()}-${filename}`

  await s3.send(new PutObjectCommand({
    Bucket: "developer-resumes",
    Key: key,
    Body: file,
    ContentType: "application/pdf"
  }))

  return `https://developer-resumes.s3.amazonaws.com/${key}`
}
Enter fullscreen mode Exit fullscreen mode

S3 is globally durable storage. Storing 10 GB of files costs roughly twenty cents per month. Scaling storage is no longer part of your architecture problem.


SQS Moves Slow Work Out of Your API

Sending emails, generating PDFs, and updating analytics inside an API request slows everything down.

Queues decouple the request from the heavy work.

Before

app.post("/apply", async (req, res) => {
  await prisma.application.create({ data: req.body })

  await sendEmail(req.body.companyEmail)
  await updateAnalytics(req.body.jobId)

  res.json({ success: true })
})
Enter fullscreen mode Exit fullscreen mode

After

import { SQSClient, SendMessageCommand } from "@aws-sdk/client-sqs"

const sqs = new SQSClient({ region: "us-east-1" })

export async function queueApplication(data) {
  await sqs.send(new SendMessageCommand({
    QueueUrl: process.env.APPLICATION_QUEUE,
    MessageBody: JSON.stringify(data)
  }))
}
Enter fullscreen mode Exit fullscreen mode

A separate Lambda consumes the queue and processes tasks asynchronously. Your API responds in milliseconds instead of seconds.

This pattern also prevents lost work if a worker crashes.


CloudFront Makes Your App Fast Worldwide

Serving static assets directly from your origin server creates huge latency for global users.

A CDN caches assets near users.

Before

User -> US server -> React bundle
Enter fullscreen mode Exit fullscreen mode

After

User -> CloudFront edge -> cached React bundle
Enter fullscreen mode Exit fullscreen mode

Example configuration:

const distribution = {
  Origins: [{
    DomainName: "frontend-assets.s3.amazonaws.com"
  }],
  DefaultCacheBehavior: {
    ViewerProtocolPolicy: "redirect-to-https",
    Compress: true
  }
}
Enter fullscreen mode Exit fullscreen mode

For international traffic this often reduces page load time by 40 to 60 percent.


Infrastructure as Code Replaces Manual AWS Setup

Many developers configure AWS through the console. That makes infrastructure impossible to reproduce.

Infrastructure should live in your repository.

Before

Manual setup steps

1. Create Lambda
2. Create API Gateway
3. Attach permissions
4. Configure environment variables
Enter fullscreen mode Exit fullscreen mode

After

import { Stack } from "aws-cdk-lib"
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"
import * as apigateway from "aws-cdk-lib/aws-apigateway"

export class ApiStack extends Stack {
  constructor(scope, id) {
    super(scope, id)

    const getJobs = new NodejsFunction(this, "GetJobs", {
      entry: "lambda/getJobs.ts"
    })

    const api = new apigateway.RestApi(this, "Api")

    api.root.addResource("jobs").addMethod(
      "GET",
      new apigateway.LambdaIntegration(getJobs)
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

The entire infrastructure becomes version controlled code.

Changes go through pull requests just like application logic.

If you want to go deeper on the deployment side, the production pipeline described in the CI/CD pipeline patterns JavaScript teams use in production shows how teams automate these deployments.


Structured Logging Makes Serverless Debuggable

When you cannot SSH into servers, logs become your only debugging tool.

Structured logging makes them searchable.

Before

console.log("Fetching jobs")
console.log(jobs)
Enter fullscreen mode Exit fullscreen mode

After

function log(level: string, message: string, data = {}) {
  console.log(JSON.stringify({
    level,
    message,
    timestamp: new Date().toISOString(),
    ...data
  }))
}

log("info", "Jobs fetched", {
  count: jobs.length,
  duration: Date.now() - startTime
})
Enter fullscreen mode Exit fullscreen mode

With structured logs you can query production behavior using CloudWatch Insights and identify bottlenecks quickly.


Developers who know React and Node can build applications. Developers who know these AWS patterns can run them in production. That difference is why companies increasingly expect JavaScript engineers to own infrastructure as well as code.

Pick one of these patterns and implement it in a small side project this week. Once you deploy your own serverless API, cloud architecture stops feeling abstract and starts feeling like a normal part of development.

Top comments (0)