In this post, I walk you through how I built and deployed a 3-tier full-stack application using AWS services. The project combines Infrastructure as Code with Terraform, CI/CD with GitHub Actions, and frontend hosting with AWS Amplify.
This guide is ideal for DevOps engineers, cloud practitioners, and developers looking to bridge the gap between application code and scalable infrastructure.
What Is a 3-Tier App?
A 3-tier architecture is a classic design pattern that divides an application into three distinct layers:
Presentation Layer (Frontend)
The user interface users interact with.
๐ In this project: a React.js app hosted on AWS Amplify.Application Layer (Backend)
Handles business logic and API processing.
๐ Here: a Node.js API deployed on an EC2 instance behind a Load Balancer.Data Layer (Database)
Responsible for storing and retrieving data.
๐ In this case: a PostgreSQL database deployed in a private subnet on AWS.
Why Use 3 Tiers?
- Separation of concerns โ Each tier is independently scalable and maintainable.
- Security โ Sensitive data stays isolated in the private network.
- Scalability โ Easily grow or debug specific components.
This architecture is widely adopted in real-world production systems and aligns perfectly with modern DevOps workflows.
Project Overview
This deployment setup uses two open-source apps to showcase DevOps automation workflows and infrastructure practices:
Backend API
A Node.js + TypeScript app using Express and Prisma ORM, connected to PostgreSQL.
๐ Repo: gabbyTI/nodejs-simple-api-with-dbFrontend
A minimal React app that communicates with the backend via API requests.
๐ Repo: gabbyTI/react-simpleapi-frontend
The focus isnโt on complex application logic โ itโs on demonstrating how to deploy and manage full-stack apps on AWS using Terraform, CI/CD, and AWS-native services.
Architecture Diagram
Hereโs the high-level infrastructure design:
Components Breakdown
- A VPC with public and private subnets across two Availability Zones
- Application Load Balancer (ALB) routes traffic to the backend
- EC2 instance hosts the Node.js app
- PostgreSQL deployed in a private subnet (via RDS or manually)
- AWS Amplify hosts and deploys the frontend from GitHub
- IAM roles, security groups, and routing are defined via Terraform
Infrastructure as Code with Terraform
All infrastructure lives in the infrastructure/
folder of the backend repo. Using Terraform ensures the setup is reproducible, modular, and version-controlled.
๐ Infra Code: infrastructure/
Key AWS Resources
-
aws_vpc
, subnets, route tables, internet/NAT gateways -
aws_security_group
for EC2 and RDS -
aws_alb
, listeners, and target groups -
aws_instance
for the backend app -
aws_db_instance
for PostgreSQL
Each resource is modularized for reusability. The infrastructure README includes setup instructions.
Backend CI/CD with GitHub Actions
The backend API is deployed to an EC2 instance via a GitHub Actions pipeline triggered on pushes to the main
branch.
CI/CD Workflow
Multi-version Node Testing
The code is tested against Node.js versions 22, 23, and 24.Artifact Packaging
After testing, an artifact containing the compiled app and environment files is prepared.Deployment to EC2
- Artifact is securely copied via
scp
-
On the EC2 instance:
- Old files are cleared
- Dependencies are installed
-
.env
is generated using GitHub Secrets - TypeScript is compiled
- Prisma migrations are applied
- Dev dependencies are pruned
- App is restarted using
pm2
All secrets (e.g., DB URLs, SSH keys) are securely managed via GitHub Secrets and Encrypted Variables.
GitHub Actions Workflow (Simplified)
name: Deploy to EC2
on:
push:
branches: [ "main" ]
jobs:
test:
strategy:
matrix:
node-version: [22, 23, 24]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci && npm test
upload-artifact:
needs: test
steps:
- run: upload app files as artifact
deploy:
needs: upload-artifact
steps:
- run: download artifact
- run: scp files to EC2
- run: ssh to EC2 and:
- set up .env
- install dependencies
- run build & migrations
- prune dev deps
- reload app with pm2
Frontend Hosting with AWS Amplify
The frontend is hosted using AWS Amplify, which automatically builds and deploys on every GitHub push.
Why Amplify?
- Built-in CI/CD and GitHub integration
- Free SSL and custom domain support
- Quick to set up and deploy
I connected the frontend repo, set the build output to build/
, and Amplify took care of the rest.
Whatโs Done
โ
Full-stack app (Node.js + React) complete
โ
Infrastructure provisioned manually with Terraform
โ
CI/CD pipeline for backend using GitHub Actions
โ
Automatic frontend deployment with AWS Amplify
Whatโs Next
๐ Add infrastructure CI/CD (terraform plan
+ apply
via GitHub Actions)
๐ Integrate CloudWatch for logs and observability
๐ Set up alarms and billing alerts for cost control
Key Takeaways
- You donโt need Kubernetes to follow solid DevOps practices.
- Declarative IaC with Terraform boosts reproducibility and confidence.
- CI/CD pipelines can be simple yet powerful.
- AWS Amplify is perfect for fast and secure frontend deployments.
Letโs Connect
If you found this guide helpful, follow me or connect on LinkedIn
Feel free to โญ the repo or fork it for your own DevOps experiments:
๐ https://github.com/gabbyTI/nodejs-simple-api-with-db
Top comments (0)