This repository contains a small Bun + Express application designed to teach and demonstrate vertical vs horizontal scaling concepts, using:
- Vertical scaling on a single machine via Node.js clustering (multiple workers using all CPU cores).
- A CPU‑intensive endpoint to generate realistic load.
- A host identification endpoint tailored for horizontal scaling demos behind a load balancer.
- A Dockerfile so you can easily run this app in containers and plug it into AWS (EC2, ECS, EKS, etc.).
The infrastructure pieces (load balancers, Auto Scaling Groups, ECS, etc.) live outside this repo; this app is the workload you deploy into those environments.
-
Difference between trivial and CPU‑bound workloads
- Use
/as a fast baseline endpoint. - Use
/cputo simulate CPU‑heavy work and observe how the app behaves under stress.
- Use
-
Vertical scaling on a single instance
- Learn how
clustercan spawn one worker per CPU core. - See how using all cores on a single EC2 instance (or container host) increases throughput compared to a single process.
- Learn how
-
Horizontal scaling concepts
- Use the
/hostendpoint to see which container/instance handled a request. - When you run multiple containers/instances behind an AWS load balancer, you can visually confirm traffic distribution by observing changing hostnames.
- Use the
-
Containerizing a Bun application
- Understand how to package a Bun + Express app into a Docker image.
- Use the same image locally and in AWS (EC2 with Docker, ECS/Fargate, EKS, etc.).
-
index.ts- Defines the Express
appwith three key routes:/– Quick “Hello World” response. Great for health checks and low‑latency baseline./cpu– Runs a large CPU‑intensive loop (e.g.forloop usingMath.random()) to simulate heavy CPU load./host– Returnsos.hostname()so you can see which host/container processed the request.
- Defines the Express
-
bin.ts- The main server entrypoint that demonstrates vertical scaling:
- Uses Node’s
clustermodule. - Determines the number of CPUs via
os.cpus().length. - In the primary process, forks one worker per CPU core.
- Each worker calls
app.listen(3000)and handles incoming HTTP traffic.
- Uses Node’s
- This models scaling up a single machine to use all its cores.
- The main server entrypoint that demonstrates vertical scaling:
-
Dockerfile- Builds a production‑ready container image:
FROM oven/bun:latest- Copies the app into
/app. - Runs
bun installfor dependencies. - Exposes port
3000. - Starts the clustered server with
CMD ["bun", "bin.ts"].
- Builds a production‑ready container image:
-
package.json- Bun‑based TypeScript project configuration:
type: "module",module: "index.ts".- Dependencies:
express,@types/express. - Dev tooling:
@types/bun, peer dep ontypescript.
- Bun‑based TypeScript project configuration:
-
tsconfig.json,bun.lock,.gitignore- Standard TypeScript/Bun project and tooling configuration.
Local requirements
- Bun installed (v1.2.2 or later recommended).
- Node.js (for tooling/TypeScript ecosystem; runtime is Bun).
- Docker (optional, only needed if you want to build/run the container image).
AWS requirements (for full scaling demos)
- An AWS account.
- IAM permissions to:
- Create and manage EC2 instances or ECS/EKS resources.
- Create load balancers (ALB/NLB) and target groups.
- Create Auto Scaling Groups or configure ECS Service autoscaling.
- Push container images to ECR (or another registry).
bun installIf you want to run the app in a single process (no clustering, useful as a baseline):
bun run index.tsNote: For full demos we typically start via
bin.ts(see below), which sets up clustering and listens on port3000. Make sure yourindex.ts(orbin.ts) callsapp.listen(3000)appropriately.
To see vertical scaling in action with one machine using all its CPU cores:
bun bin.tsThis will:
- Start a primary (master) process.
- Fork one worker per CPU core.
- Have each worker listen on
http://localhost:3000.
Now, in another terminal:
-
Fast endpoint (baseline):
curl http://localhost:3000/
-
CPU‑intensive endpoint:
curl http://localhost:3000/cpu
Compare:
- Running
bun run index.ts(single process) vs - Running
bun bin.ts(multi‑process via clustering)
under sustained load (e.g. with ab, wrk, k6, or hey) to observe the benefits of vertical scaling on a single host.
This repo does not ship with AWS IaC (Terraform/CDK/CloudFormation), but the app is intentionally designed to be plugged into a horizontally scaled setup:
-
Build and tag the Docker image
docker build -t aws-scaling-demo . -
Run locally as a container
docker run --rm -p 3000:3000 aws-scaling-demo
-
Push to a registry (e.g. ECR)
Tag and push the image to your ECR repo or preferred registry. -
Create multiple instances/containers in AWS
- EC2 + Docker: Launch multiple EC2 instances running this container.
- ECS/Fargate: Create a Task Definition and Service using this image.
- EKS/Kubernetes: Create a Deployment using this image and multiple replicas.
-
Front them with a load balancer
- Use an Application Load Balancer (ALB) or equivalent.
- Point the target group to your EC2 instances, ECS service, or Kubernetes Service.
-
Use the
/hostendpoint to visualize horizontal scalingCall:
curl http://<load-balancer-dns>/host
multiple times and observe the hostname (or pod/container ID) changing over time. This shows requests being distributed across multiple instances—horizontal scaling.
Combine this with load testing on /cpu to:
- See how adding more instances (horizontal scaling) affects throughput/latency.
- Compare that with upgrading to bigger instances (vertical scaling via more vCPUs + clustering).
You can use this repo as a practical component in an AWS scaling course or workshop:
-
Step 1 – Local understanding
- Run single‑process vs clustered server.
- Observe CPU utilization and response times for
/vs/cpu.
-
Step 2 – Vertical scaling on AWS
- Deploy the container to a single EC2 instance or ECS task.
- Use bigger EC2 instance types (more vCPUs/RAM) and enable clustering.
- Measure performance as you “scale up”.
-
Step 3 – Horizontal scaling on AWS
- Run multiple instances/tasks.
- Put an ALB in front.
- Use
/hostand/cputo:- Confirm load balancing.
- Compare behavior as you increase the number of instances (“scale out”).
This clear comparison helps cement when to scale up vs when to scale out, and how application design (clustered workers, CPU‑bound workloads, containerization) interacts with AWS infrastructure.
This project was originally bootstrapped with bun init using Bun v1.2.2.
Bun is a fast all‑in‑one JavaScript runtime that includes a JavaScript/TypeScript engine, bundler, test runner, and package manager.