DEV Community

Cover image for Deploying a 3-Tier Full-Stack App on AWS with Terraform, GitHub Actions, and Amplify (Node.js + React)
Gabriel
Gabriel

Posted on

Deploying a 3-Tier Full-Stack App on AWS with Terraform, GitHub Actions, and Amplify (Node.js + React)

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:

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:

3-Tier AWS Architecture

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

  1. Multi-version Node Testing
    The code is tested against Node.js versions 22, 23, and 24.

  2. Artifact Packaging
    After testing, an artifact containing the compiled app and environment files is prepared.

  3. 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
Enter fullscreen mode Exit fullscreen mode

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)