Connecting from Cloud Functions to Cloud SQL

This page contains information and examples for connecting to a Cloud SQL instance from a service running in Cloud Functions.

Cloud SQL is a fully-managed database service that helps you set up, maintain, manage, and administer your relational databases in the cloud.

Cloud Functions is a lightweight compute solution for developers to create single-purpose, standalone functions that responds to Cloud events without the need to manage a server or runtime environment.

Setting up a Cloud SQL instance

  1. Enable the Cloud SQL Admin API in the project you are connecting from, if you haven't already done so:

    Enable the API

  2. Create a Cloud SQL for PostgreSQL instance.

    By default, Cloud SQL assigns a public IP address to a new instance. You also have the option to assign a private IP address. For more information about the connectivity options for both, see the Connecting Overview page.

Configuring Cloud Functions

The steps to configure Cloud Functions depend on the type of IP address you assigned to your Cloud SQL instance.

Public IP (default)

To configure Cloud Functions to enable connections to a Cloud SQL instance:

  • Make sure that the instance created above has a public IP address. You can verify this on the Overview page for your instance in the Google Cloud Console. If you need to add one, see the Configuring public IP page for instructions.
  • Get the INSTANCE_CONNECTION_NAME for your instance. This can be found on the Overview page for your instance in the Google Cloud Console. or by running the following command: gcloud sql instances describe [INSTANCE_NAME].
  • Ensure that the service account your function is using to authenticate calls to Cloud SQL has the appropriate Cloud SQL roles and permissions.
    • The service account for your service needs one of the following IAM roles:
      • Cloud SQL Client (preferred)
      • Cloud SQL Editor
      • Cloud SQL Admin
      Or, you can manually assign the following IAM permissions:
      • cloudsql.instances.connect
      • cloudsql.instances.get
      For detailed instructions on adding IAM roles to a service account, see Granting Roles to Service Accounts.

    By default, your app will authorize your connections using the Cloud Functions service account. The service account is in the format service-PROJECT_NUMBER@gcf-admin-robot.iam.gserviceaccount.com.

    If the authorizing service account belongs to a different project than the Cloud SQL instance, the Cloud SQL Admin API and IAM permissions will need to be added for both projects.

Private IP

A Serverless VPC Access connector handles communication to your VPC network. To connect directly with private IP, you need to:

  1. Make sure that the Cloud SQL instance created above has a private IP address. If you need to add one, see the Configuring private IP page for instructions.
  2. Create a Serverless VPC Access connector in the same VPC network as your Cloud SQL instance.
  3. Unless you're using Shared VPC, a connector must be in the same project and region as the resource that uses it, but the connector can send traffic to resources in different regions.

    Serverless VPC Access supports communication to VPC networks connected via Cloud VPN and VPC Network Peering.

    Serverless VPC Access does not support legacy networks.

  4. Configure Cloud Functions to use the connector.
  5. Connect using your instance's private IP and port 5432.

Connecting to Cloud SQL

After you configure Cloud Functions, you can connect to your Cloud SQL instance. Cloud Functions provides a mechanism that connects using the Cloud SQL Proxy.

Public IP (default)

Private IP

Connecting with TCP

Connect directly using the private IP address and port 5432 for your instance.

Python

To see this snippet in the context of a web application, view the README on GitHub.

# Remember - storing secrets in plaintext is potentially unsafe. Consider using
# something like https://cloud.google.com/secret-manager/docs/overview to help keep
# secrets secret.
db_user = os.environ["DB_USER"]
db_pass = os.environ["DB_PASS"]
db_name = os.environ["DB_NAME"]
db_host = os.environ["DB_HOST"]

# Extract host and port from db_host
host_args = db_host.split(":")
db_hostname, db_port = host_args[0], int(host_args[1])

pool = sqlalchemy.create_engine(
    # Equivalent URL:
    # postgres+pg8000://<db_user>:<db_pass>@<db_host>:<db_port>/<db_name>
    sqlalchemy.engine.url.URL(
        drivername="postgresql+pg8000",
        username=db_user,  # e.g. "my-database-user"
        password=db_pass,  # e.g. "my-database-password"
        host=db_hostname,  # e.g. "127.0.0.1"
        port=db_port,  # e.g. 5432
        database=db_name  # e.g. "my-database-name"
    ),
    **db_config
)

Node.js

To see this snippet in the context of a web application, view the README on GitHub.

const connectWithTcp = config => {
  // Extract host and port from socket address
  const dbSocketAddr = process.env.DB_HOST.split(':'); // e.g. '127.0.0.1:5432'

  // Establish a connection to the database
  return Knex({
    client: 'pg',
    connection: {
      user: process.env.DB_USER, // e.g. 'my-user'
      password: process.env.DB_PASS, // e.g. 'my-user-password'
      database: process.env.DB_NAME, // e.g. 'my-database'
      host: dbSocketAddr[0], // e.g. '127.0.0.1'
      port: dbSocketAddr[1], // e.g. '5432'
    },
    // ... Specify additional properties here.
    ...config,
  });
};

Go

To see this snippet in the context of a web application, view the README on GitHub.

var (
	dbUser    = mustGetenv("DB_USER")     // e.g. 'my-db-user'
	dbPwd     = mustGetenv("DB_PASS")     // e.g. 'my-db-password'
	dbTcpHost = mustGetenv("DB_TCP_HOST") // e.g. '127.0.0.1' ('172.17.0.1' if deployed to GAE Flex)
	dbPort    = mustGetenv("DB_PORT")     // e.g. '5432'
	dbName    = mustGetenv("DB_NAME")     // e.g. 'my-database'
)

var dbURI string
dbURI = fmt.Sprintf("host=%s user=%s password=%s port=%s database=%s", dbTcpHost, dbUser, dbPwd, dbPort, dbName)

// dbPool is the pool of database connections.
dbPool, err := sql.Open("pgx", dbURI)
if err != nil {
	return nil, fmt.Errorf("sql.Open: %v", err)
}

// ...

return dbPool, nil

Best practices and other information

You can use the Cloud SQL proxy when testing your application locally. See the quickstart for using the proxy for local testing for detailed instructions.

Connection Pools

Connections to underlying databases may be dropped, either by the database server itself, or by the infrastructure underlying Cloud Functions. We recommend using a client library that supports connection pools that automatically reconnect broken client connections. Additionally, we recommend using a globally scoped connection pool to increase the likelihood that your function reuses the same connection for subsequent invocations of the function, and closes the connection naturally when the instance is evicted (auto-scaled down). For more detailed examples on how to use connection pools, see Managing database connections.

Connection Limits

Cloud SQL imposes a maximum limit on concurrent connections, and these limits may vary depending on the database engine chosen (see Cloud SQL Quotas and Limits). It's recommended to use a connection with Cloud Functions, but it is important to set the maximum number of connections to 1.

Where possible, you should take care to only initialize a connection pool for functions that need access to your database. Some connection pools will create connections preemptively, which can consume excess resources and count towards your connection limits. For this reason, it's recommended to use Lazy Initialization to delay the creation of a connection pool until needed, and only include the connection pool in functions where it's used.

For more detailed examples on how to limit the number of connections, see Managing database connections.

API Quota Limits

Cloud Functions provides a mechanism that connects using the Cloud SQL Proxy, which uses the Cloud SQL Admin API. API quota limits apply to the Cloud SQL Proxy.