Goal: a Cloud Run service talking to Cloud SQL without exposing the database to the public internet more than necessary.
Path A - public IP instance (simplest):
```
gcloud run deploy [SERVICE] --image [IMAGE] --region [REGION] --add-cloudsql-instances [PROJECT]:[REGION]:[INSTANCE]
```
Your code connects via the Cloud SQL Python/Node connectors or a unix socket at /cloudsql/[CONNECTION-NAME]. The --add-cloudsql-instances flag wires the Cloud SQL Auth Proxy sidecar for you.
Path B - private IP instance (recommended for prod):
- Route egress through Direct VPC egress or a Serverless VPC Access connector, and use the instance's private IP.
- Direct VPC egress is the newer path; the Serverless VPC Access connector is the older one. Compare them in the docs before choosing; both are documented.
- The Cloud Run service account needs cloudsql.client (roles/cloudsql.client) on the instance.
Ordering:
1. Create the Cloud SQL instance first, note the connection name.
2. Create the SA for the service, grant cloudsql.client.
3. Deploy with --add-cloudsql-instances (public) or VPC egress config (private).
4. Test connectivity from the deployed revision, not just locally. Local tests use your credentials; prod uses the SA.
Traps:
- Mixing paths: --add-cloudsql-instances with a private-IP-only instance fails. Match the method to the IP type.
- Forgetting the SA grant gives connection errors that look like network issues. Check IAM before debugging VPC.
- Connection pooling: use the language connectors with pooling; opening a fresh connection per request exhausts the instance.
Verify: hit an endpoint that queries the DB, check query latency in Cloud SQL insights, and confirm no public-IP connections if you intended private-only.