Skip to content
 
 

Latest commit

 

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

example-three-tier-application

A reference implementation of a three-tier web application: a Next.js frontend, an Express REST API, and a PostgreSQL database. It runs locally with Docker Compose and deploys to Google Cloud Platform (Cloud Run + Cloud SQL) via Terraform.

Architecture

Browser → Web (Next.js :3000) → API (Express :3001) → PostgreSQL
Layer Technology Location
Frontend Next.js 16, React 19, Tailwind CSS src/web/
API Express 5, Node.js 22 src/api/
Database PostgreSQL 17 managed by Docker / Cloud SQL
Migrations node-pg-migrate src/db/
Infrastructure Terraform (GCP) src/infrastructure/

The app is a simple task manager (to-do list) that demonstrates how the three tiers communicate.

Running locally with Docker Compose

Prerequisites

Start the stack

docker compose up --build

This starts four services in order:

  1. postgres — PostgreSQL 17 database, waits until healthy
  2. migrate — runs node-pg-migrate up to apply schema migrations, then exits
  3. api — Express API on port 3001 (internal only)
  4. web — Next.js frontend on port 3000 (exposed to host)

Once running, open http://localhost:3000.

Stop and clean up

# Stop containers (keeps the postgres_data volume)
docker compose down

# Stop and delete all data
docker compose down -v

Rebuild after code changes

docker compose up --build

API endpoints

The API is not exposed directly, but you can reach it through the web container or by temporarily mapping its port:

Method Path Description
GET /health Health check
GET /tasks List all tasks
POST /tasks Create a task ({ "title": "..." })
PATCH /tasks/:id Update a task ({ "completed": true } or { "title": "..." })

Project structure

src/
├── api/            # Express REST API
│   ├── index.js    # Route handlers
│   ├── db.js       # PostgreSQL connection pool
│   └── Dockerfile
├── db/             # Database migrations
│   ├── migrations/ # node-pg-migrate migration files
│   └── Dockerfile
├── web/            # Next.js frontend
│   ├── app/        # App Router pages and components
│   └── Dockerfile
└── infrastructure/ # Terraform for GCP deployment
    ├── main.tf
    ├── variables.tf
    └── outputs.tf

Deploying to GCP

The src/infrastructure/ directory contains Terraform that provisions:

  • VPC network and subnet
  • Cloud SQL PostgreSQL 17 instance (private IP)
  • Cloud Run services for the API and web frontend
  • Secret Manager secret for the database URL
  • Service accounts and IAM bindings

Required variables

Variable Description
project_id GCP project ID
api_image Container image URI for the API (e.g. gcr.io/PROJECT/api:TAG)
web_image Container image URI for the web frontend
region GCP region (default: us-central1)
environment dev, staging, or prod (default: dev)
cd src/infrastructure
terraform init
terraform apply -var="project_id=my-project" \
                -var="api_image=gcr.io/my-project/api:latest" \
                -var="web_image=gcr.io/my-project/web:latest"

After apply, terraform output web_url gives the public URL.

Database migrations

Migrations live in src/db/migrations/ and use node-pg-migrate.

# Apply all pending migrations (run inside the db container or with DATABASE_URL set)
cd src/db
DATABASE_URL=postgres://app:app@localhost:5432/app npx node-pg-migrate up

# Roll back the last migration
DATABASE_URL=postgres://app:app@localhost:5432/app npx node-pg-migrate down

When running via Docker Compose the migrate service handles this automatically on startup.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages