This repository shows a minimal full-stack application that can be deployed entirely on low-cost, fully managed Google Cloud services. It contains three parts:
app/: Node.js + Express web/API service that serves a static page and exposes REST endpoints.infra/terraform/: Terraform configuration (the Google Cloud–recommended IaC approach) that creates Firestore, Artifact Registry, required APIs, and the Cloud Run service account.- Deployment flow: use the
gcloudCLI to build/push the container image and deploy the Cloud Run service. Firestore provides the managed data tier, so the solution includes UI + API + database.
High-level architecture: Browser → Cloud Run service → /api/messages endpoints → Firestore for persistence. Everything runs on serverless, pay-per-use infrastructure.
cd app
npm install
npm start
# open http://localhost:8080The server reads Firestore using local Google Cloud credentials. Run gcloud auth application-default login and enable Firestore in your project if you want to test against GCP.
cd infra/terraform
cp terraform.tfvars.example terraform.tfvars
# edit terraform.tfvars and set project_id / region / firestore_location
terraform init
terraform applyTerraform performs the following:
- Enables Cloud Run, Artifact Registry, Firestore, Cloud Build, and Secret Manager APIs
- Creates an Artifact Registry repo for the container image
- Creates the Cloud Run runtime service account with Firestore/logging/monitoring permissions
- Initializes a
FIRESTORE_NATIVEdatabase if the project does not already have one
Terraform outputs the Artifact Registry repository path and the service account email. Assume:
- Project:
PROJECT_ID - Region:
REGION - Repository:
REGION-docker.pkg.dev/PROJECT_ID/guestbook-web - Service name:
guestbook-service
Deployment steps (can be scripted):
gcloud config set project PROJECT_ID
gcloud auth configure-docker ${REGION}-docker.pkg.dev
# Build and push (Cloud Build, pay-per-use)
gcloud builds submit ./app \
--region=REGION \
--tag=${REGION}-docker.pkg.dev/PROJECT_ID/guestbook-web/guestbook:$(git rev-parse --short HEAD)
# Deploy Cloud Run
gcloud run deploy guestbook-service \
--image=${REGION}-docker.pkg.dev/PROJECT_ID/guestbook-web/guestbook:$(git rev-parse --short HEAD) \
--region=REGION \
--allow-unauthenticated \
--service-account=$(terraform output -raw cloud_run_service_account) \
--set-env-vars=FIRESTORE_COLLECTION=messages,MAX_MESSAGES=20gcloud run deploy prints a public HTTPS URL once provisioning finishes. Open it in a browser to interact with Firestore-backed APIs.
.
├── app/ # Web + API service
│ ├── src/server.js # Express entry point
│ ├── public/ # Static assets
│ └── Dockerfile # Cloud Run container image
├── infra/terraform/ # IaC configuration
│ ├── main.tf # Resource definitions
│ └── terraform.tfvars.example
└── README.md
- Cloud Run (Gen1/Gen2): Serverless container runtime with per-request billing and zero cost when idle.
- Firestore (Native mode): Managed NoSQL datastore with a generous free tier for small workloads.
- Cloud Build + Artifact Registry: Pay only for builds and stored images; no always-on VM expenses.
- All resources can be destroyed when not needed with
terraform destroyto avoid residual costs.
- Map a custom HTTPS domain to the Cloud Run service and optionally front it with Cloud CDN.
- Extend Terraform to include a
google_cloud_run_v2_serviceresource for fully automated deployments. - Protect POST endpoints with IAP, OAuth, or signed JWTs before using the app in production.