How I Deployed a Scalable NestJS Backend to Google Cloud for ~$10/Month

Source: Dev.to | Jan 05, 2026 (UTC)

As a solopreneur, my biggest nightmare isn’t a bug in production it’s waking up to a $500+ cloud bill for a side project that has zero users.

When building Mockline, I needed a robust backend (NestJS) and a reliable relational database (PostgreSQL). The default recommendation for Google Cloud SQL (Enterprise tier) often starts at $50-100/month just for the database. If you add high availability and dedicated cores, you are easily looking at $300+.

This guide documents how I engineered a production ready stack using Cloud Run (Serverless) and a Cloud SQL Micro Instance for roughly $10/month.

The Code (nestjs): Listening on 0.0.0.0

Before we touch the cloud, we need to fix a common NestJS default. By default, NestJS often listens on localhost. Cloud Run containers need to listen on 0.0.0.0 to receive traffic from the load balancer.

async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableCors({ origin: ['https://mywebsite.com', process.env.FRONTEND_URL].filter(Boolean), credentials: true, }); const port = process.env.PORT || 3000; // CRITICAL: Bind to 0.0.0.0, not just localhost await app.listen(port, '0.0.0.0'); console.log(`Application is running on: ${await app.getUrl()}`); } bootstrap();

Enter fullscreen mode

Exit fullscreen mode

If you miss the ‘0.0.0.0’ part (which i did, silly I know but it happens), your Cloud Run deployment will fail with a generic “Container failed to start” error because the health check can’t reach your app.

The $10 Database (Cloud SQL)

This is where the magic happens. We are going to ignore the “Recommended” production settings (which assume you are Netflix or Amazon) and pick the Shared Core tier.

Specs for the Budget Instance:

Tier: db-f1-micro

Region: asia-south1 (Mumbai) — Pick the one closest to you/users

Availability: Single Zone (You can change it to Multiple zones for Highly available anytime later)

Storage: 10GB SSD

Create the instance via CLI:

gcloud sql instances create prasun-db \ --database-version=POSTGRES_17 \ --cpu=1 \ --memory=614MiB \ --region=asia-south1 \ --root-password=prasunpass2026!

Enter fullscreen mode

Exit fullscreen mode

Once created, create the actual database inside the instance:

gcloud sql databases create prasun-db --instance=prasun-db

Enter fullscreen mode

Exit fullscreen mode

Cloud Run doesn’t talk to Cloud SQL via IP address (usually). It uses a Unix Socket. You need the Connection Name:

gcloud sql instances describe prasun-db --format="value(connectionName)" # Output looks like: project-id:region:instance-name

Enter fullscreen mode

Exit fullscreen mode

Deployment & IAM Permissions

This is the tricky part which takes lot of time, if not done right
The Cloud Run service account needs permission to “talk” to the database.

Grant Permissions: Find your Compute Engine default service account (or the custom one you are using) and grant it the Cloud SQL Client role.

# Get your project number PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value project) --format="value(projectNumber)") SERVICE_ACCOUNT="${PROJECT_NUMBER}[email protected]" # Grant the 'Cloud SQL Client' role gcloud projects add-iam-policy-binding $(gcloud config get-value project) \ --member=serviceAccount:${SERVICE_ACCOUNT} \ --role=roles/cloudsql.client

Enter fullscreen mode

Exit fullscreen mode

We will deploy directly from the source using gcloud run deploy. This handles the Docker build for us automatically (if you have a Dockerfile).

gcloud run deploy mockline-nestjs \ --source . \ --region asia-south1 \ --allow-unauthenticated \ --add-cloudsql-instances [YOUR_CONNECTION_NAME] \ --set-env-vars NODE_ENV=production \ --set-env-vars DATABASE_USER=postgres \ --set-env-vars DATABASE_NAME=prasun-db \ --set-env-vars DATABASE_PORT=5432 \ --set-env-vars FRONTEND_URL=https://mywebsite.com --set-env-vars DATABASE_HOST=/cloudsql/[YOUR_CONNECTION_NAME] \ --set-env-vars DATABASE_PASSWORD=[YOUR_DB_PASSWORD]

Enter fullscreen mode

Exit fullscreen mode

Troubleshooting: Why? 🛑

If you see the dreaded red exclamation mark (which you shouldn’t see because this is a tried and tested method), I will list down the one’s i faced:

  1. connect ECONNREFUSED .../cloudsql/.../.s.PGSQL.5432 Reason: Your app tried to connect, but the socket wasn’t there.

Fix: Did you forget the –add-cloudsql-instances flag? Or did you forget to grant the roles/cloudsql.client IAM permission?

  1. “Container failed to start and listen on port 8080” Reason: Your NestJS app started, but Cloud Run couldn’t hear it.

Fix: Go back to main.ts. Are you listening on 0.0.0.0?

  1. “database does not exist” Reason: You created the SQL Instance, but not the Database inside it.

Fix: Run gcloud sql databases create [db_name] –instance=[instance_name].

Conclusion

You don’t need a venture capital budget to run enterprise-grade tools. By using a shared core Micro Instance and Cloud Run, you get the best of both worlds: a managed relational database and a serverless backend that scales to zero when you sleep.

For further actions, you may consider blocking this person and/or reporting abuse

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

Читайте також