Scaling Node.js application using Auto Scaling Groups

Brief Intro to ASG
An Auto Scaling Group (ASG) in AWS (Amazon Web Services) is a service that automatically adjusts the number of EC2 (Elastic Compute Cloud) instances in a specified group to meet the demand for your application. It helps ensure that you have the right amount of compute capacity at any given time by automatically scaling up (adding more instances) or scaling down (removing instances) based on demand. This helps optimize costs and ensures that your application is always running efficiently.
In this blog we will see how to create an ASG for a Node.js application.
Step 1 : Start an EC2 instance on AWS
In your AWS console create a new EC2 instance. Choose Ubuntu as the OS for the instance and other configurations like instance type and storage as per the project requirements.
Create a new or select an existing SSH key pair. This will allow you to ssh into you EC2 instance.
#To ssh into your EC2 instance. Run the following command from you CLI ssh -i <your-ssh-private-key> ubuntu@<your-instance-public-ip>
After creating an EC2 instance. Install nodejs on the machine.
Refer to this url for installing node on ubuntu machine:
https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04
Clone the repo from the GitHub on your AWS instance.
# Clone your Node.js app from GitHub
git clone https://github.com/your-username/your-repo.git
# Move into the project directory
cd your-repo
# Install dependencies
npm install
# Start the app
npm start
Code Example:
import express from "express";
import os from "os";
export const app = express();
app.get("/", (req, res) => {
res.send("Hello World");
});
app.get("/cpu", (req, res) => {
for (let i = 0; i < 1000000000; i++) {
Math.random();
}
res.send("Hello World");
});
app.get("/host", (req, res) => {
res.send(os.hostname());
});
app.listen(3000, () => {
console.log(`Worker ${process.pid} started`);
});
Note: Make sure your package.json has the necessary scripts so the app can run properly.
How I prefer to write my scripts for a typescript code:
"scripts": {
"build": "tsc -b",
"start": "node dist/bin.js",
"dev": "ts-node src/bin.ts"
},
You can also skip the script part and add another package called PM2 which is the process management for the nodejs applications.
npm install -g pm2
pm2 start server.js
Step 2 : Creating an AMI (Amazon Machine Image)
AMI is a pre-configured template used to create a virtual server of an EC2 instance. You need AMI to create a launch template (which we will discuss in next step).
AMI will contain the operating system, application software that you have installed on the EC2 instance that the image has been created from.
Navigate to instances on EC2 dashboard.
Select the instance that you created and in the actions tab create a new image from it.
After creating an AMI from your instance, it is time to create a launch template from it.
Step 3 : Creating a Launch Template
In AWS, a Launch Template is a resource that defines the configuration settings used to launch EC2 instances. It acts as a blueprint that specifies the instance configuration, such as instance type, Amazon Machine Image (AMI), security groups, key pairs, storage, and other parameters, making it easier to launch instances with predefined configurations.
Navigate to EC2 Dashboard → Launch Templates.
Click Create launch template.
Select the AMI you created earlier with Node.js + your app installed.
This ensures every new EC2 instance launched will have your environment ready.
Pick a suitable instance size. I prefer to keep the EC2 instance size (that was created in step 1) and launch template size same.
Create a new or choose an existing SSH keypair. SSH keypair will let you ssh into your EC2 instances that will be launched by ASG.
Advance details Important step
In User Data, add a script to make sure your Node.js app (or PM2) starts automatically when the instance boots.
Example:
#!/bin/bash cd /home/ec2-user/my-node-app npm install --production pm2 start server.js --name my-node-app pm2 startup systemd pm2 save
Click on create a launch template.
Understanding the Architecture: How autoscaling groups work with load balancers and target groups
Before we move forward with creating the Launch Template and Auto Scaling Group, let’s first understand the bigger picture. The following diagram shows how your Node.js application will be deployed on AWS using:
Auto Scaling Group (ASG): Automatically adds or removes EC2 instances based on traffic.
Elastic Load Balancer (ELB): Distributes incoming traffic across multiple instances.
Target Group: Keeps track of healthy instances and routes requests accordingly.
Exaplanation:
User request → comes in through the internet.
Load Balancer → receives the request and forwards it to the target group.
Target Group → contains the healthy EC2 instances in the ASG.
Auto Scaling Group → monitors CPU/traffic and scales the number of EC2 instances up or down.
Step 4 : Creating a target group
Navigate to EC2 Dashboard → Create target group.
Choose the target type as instance as we want ASG to scale up or down our EC2 instances.
Give your target group a suitable name.
Select HTTP on port 80 (or the port your Node.js app is running on, e.g., 3000).
Configure Health Checks Important
Protocol: HTTP.
Path: / (or /health if you’ve set up a health endpoint in your app).
This ensures the load balancer only forwards traffic to healthy instances.
Health checks are like regular “check-ups” to make sure your targets (servers, containers, or Lambdas) are healthy before sending them traffic.
- Click create target groups.
Step 5 : Creating an ASG
Navigate to EC2 Dashboard → Auto Scaling Group → Create Auto Scaling Group.
Select launch template that you created earlier (with your AMI and user data)
Confgure the ASG nework settings as per the requirements.
In the integrating with other services section. Create a new or attach an existing load balancer to your ASG.
If creating a new follow the following steps:
Choose Application Load Balancer (ALB).
Scheme: Internet-facing.
Listeners: Add listener on HTTP port 80.
Availability Zones: Select at least two subnets.
Target Groups: Select the target group you created earlier (node-js-app).
Once created, your ASG wizard will automatically pick up the new load balancer and target group.
Configuring group size and scaling policies Important
In this section you will configure what should be the desired number of EC2 instances that you want ASG to start. Also you will specify the minimum and maximum number of EC2 instances that ASG will spin up or spin down based on the incoming traffic.
Desired capacity: Start with 2 instances.
Minimum capacity: 1 (so at least one instance is always running).
Maximum capacity: e.g., 4 (depending on expected traffic).
Scaling policies: Enable dynamic scaling (e.g., add instance when CPU > 60%, remove when < 30%).
After this other sections are optional you can also set them up based on the particular requirements.
After setting up the whole ASG configuration click on the create Auto scaling group to launch you ASG.
Conclusion
In this guide, we walked through how to deploy a Node.js application on AWS using Auto Scaling Groups (ASG), Target Groups, and a Load Balancer. By following these steps, you now have an architecture that is:
Scalable – your app automatically adjusts to handle traffic spikes.
Highly available – if one instance fails, the load balancer routes traffic to healthy ones.
Cost-efficient – you only run the number of instances you actually need.
With this setup, you’ve gone beyond just running a single Node.js app on EC2 — you’ve built a foundation that can grow with your users.
I’ll be creating more blogs on topics like App Development, Web Development, and DevOps. If you found this guide helpful, make sure to follow and like so you don’t miss the next one!
Subscribe to my newsletter
Read articles from Airaad directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Airaad
Airaad
Hi, Welcome to my blog 👋 I’m interested in exploring the world of software technologies, with a focus on backend development and DevOps. I enjoy working on scalable systems, automation, and the tools that improve reliability and efficiency in software engineering. On this blog, I share my journey, insights, and learnings around: Backend architectures & frameworks Databases & APIs CI/CD pipelines & automation Cloud platforms & containerization Monitoring, security, and DevOps best practices My aim is to document what I learn, break down complex concepts, and provide useful resources for others in the field.