Skip to content

Google Cloud Functions

Cloud Functions Gen2 is GCP’s serverless compute option. It scales to zero when idle and you pay only for invocation time. It is built on Cloud Run under the hood but abstracts away container management.

  • Low or unpredictable traffic (scale-to-zero saves money)
  • Event-driven workloads (Pub/Sub, Cloud Storage triggers)
  • Simple deployments without Docker
  • You do not need waitUntil() fire-and-forget behavior

For sustained traffic, background work, or WebSocket support, use Cloud Run instead.

import { GCPCloudFunctionsAdapter } from '@cruzjs/adapter-gcp';
export default createCruzApp({
schema,
modules: [/* your modules */],
adapter: new GCPCloudFunctionsAdapter({
databaseUrl: process.env.DATABASE_URL,
gcsBucket: process.env.GCS_BUCKET,
redisUrl: process.env.REDIS_URL,
pubsubTopic: process.env.PUBSUB_TOPIC,
gcpProjectId: process.env.GCP_PROJECT_ID,
}),
pages: () => import('virtual:react-router/server-build'),
});

CruzJS exports a handler function that Cloud Functions invokes. The build output includes this entry point automatically. When deploying, set --entry-point=handler.

Terminal window
gcloud functions deploy my-cruz-app \
--gen2 \
--runtime=nodejs20 \
--region=us-central1 \
--trigger-http \
--allow-unauthenticated \
--entry-point=handler \
--source=./build \
--set-env-vars="DATABASE_URL=postgresql://cruzuser:pw@/cruzdb?host=/cloudsql/my-project:us-central1:my-cruz-db" \
--set-env-vars="AUTH_SECRET=$(openssl rand -base64 32)" \
--set-env-vars="GCS_BUCKET=my-cruz-uploads" \
--memory=512MB \
--timeout=60s \
--max-instances=10 \
--min-instances=0

Cloud Functions runs as serverless runtime type. The function execution environment is frozen after the response is returned. This means:

  • waitUntil() tasks must flush before the response is sent
  • The adapter automatically awaits all pending waitUntil() promises before responding
  • Long-running background work should use Pub/Sub or Cloud Tasks instead

If you need fire-and-forget waitUntil(), use Cloud Run with cpuAlwaysAllocated: true.

Cloud Functions instances are recycled after periods of inactivity. Cold starts add latency to the first request.

Mitigation strategies:

  • Set --min-instances=1 — keeps one instance warm (costs more, but eliminates cold starts)
  • Reduce bundle size — smaller deployments start faster
  • Use --cpu-boost — temporarily adds CPU during cold start initialization
Terminal window
gcloud functions deploy my-cruz-app \
--gen2 \
--min-instances=1 \
--cpu-boost \
...
SettingDefaultMaxNotes
Memory256MB32GBSet based on your app’s needs
Timeout60s3600s (Gen2)HTTP functions typically need 30-120s
Max instances1001000Prevents runaway scaling

Higher memory allocations also increase available CPU proportionally.

Cloud Functions Gen2 uses the same Cloud SQL connector as Cloud Run. Add the --add-cloudsql-instances flag:

Terminal window
gcloud functions deploy my-cruz-app \
--gen2 \
--add-cloudsql-instances=my-project:us-central1:my-cruz-db \
...

Then use the Unix socket connection string:

Terminal window
DATABASE_URL=postgresql://cruzuser:password@/cruzdb?host=/cloudsql/my-project:us-central1:my-cruz-db

Cloud Functions can create many instances, each opening database connections. Guard against connection exhaustion:

  • Set --max-instances to cap total instances
  • Use Cloud SQL connection pooling (PgBouncer via AlloyDB Omni or a sidecar)
  • Keep connection pool size small per instance (2-5 connections)
Terminal window
--trigger-http --allow-unauthenticated

This is what CruzJS uses for the web application handler.

Terminal window
gcloud functions deploy my-cruz-worker \
--gen2 \
--trigger-topic=cruz-jobs \
--entry-point=pubsubHandler \
--runtime=nodejs20 \
--region=us-central1

Pub/Sub-triggered functions are useful for processing background jobs published from your main CruzJS app.

FeatureCloud FunctionsCloud Run
waitUntil() fire-and-forgetNoYes (with cpuAlwaysAllocated)
WebSocket / SSENoYes
Custom DockerfileNoYes
Concurrency per instance1 (Gen1) / configurable (Gen2)Configurable
Startup timeSlower (cold start)Faster (min instances)
DeploymentSource-basedContainer-based