I am trying to deploy a PayloadCMS/Next.js app using Cloud Run, Cloud Build and Google Postgres SQL. The app needs to connect to the database during the build process via a Postgres url string (DATABASE_URI). I figured out how to pass the variables using secret mounts, but I haven't been able to connect to the database at build time using SQL proxy.
Here is my cloudbuild.yaml file:
steps:
- name: gcr.io/cloud-builders/wget
entrypoint: sh
args:
- '-c'
- |
wget -O /workspace/cloud-sql-proxy https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.16.0/cloud-sql-proxy.linux.amd64
chmod +x /workspace/cloud-sql-proxy
id: Proxy
- name: gcr.io/cloud-builders/docker:24.0.9
waitFor: ['Proxy']
entrypoint: bash
env:
- 'DOCKER_BUILDKIT=1'
args:
- '-c'
- |
/workspace/cloud-sql-proxy ${_INSTANCE_CONNECTION_NAME} --port ${_DATABASE_PORT} --structured-logs & sleep 2;
next_public_server_url=$.$next_public_server_url \
database_uri=$.$database_uri \
payload_secret=$.$payload_secret \
cron_secret=$.$cron_secret \
preview_secret=$.$preview_secret \
gcs_bucket=$.$gcs_bucket \
gcs_endpoint=$.$gcs_endpoint \
gcs_project_id=$.$gcs_project_id \
docker buildx build --network host --no-cache \
--secret id=next_public_server_url \
--secret id=database_uri \
--secret id=payload_secret \
--secret id=cron_secret \
--secret id=preview_secret \
--secret id=gcs_bucket \
--secret id=gcs_endpoint \
--secret id=gcs_project_id \
-t $_AR_HOSTNAME/$_AR_PROJECT_ID/$_AR_REPOSITORY/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA . -f Dockerfile
id: Build
secretEnv:
[
'next_public_server_url',
'database_uri',
'payload_secret',
'cron_secret',
'preview_secret',
'gcs_bucket',
'gcs_endpoint',
'gcs_project_id',
]
- name: gcr.io/cloud-builders/docker
args:
- push
- >-
$_AR_HOSTNAME/$_AR_PROJECT_ID/$_AR_REPOSITORY/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
id: Push
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:slim'
args:
- run
- services
- update
- $_SERVICE_NAME
- '--platform=managed'
- >-
--image=$_AR_HOSTNAME/$_AR_PROJECT_ID/$_AR_REPOSITORY/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
- >-
--labels=managed-by=gcp-cloud-build-deploy-cloud-run,commit-sha=$COMMIT_SHA,gcb-build-id=$BUILD_ID,gcb-trigger-id=$_TRIGGER_ID
- '--region=$_DEPLOY_REGION'
- '--quiet'
id: Deploy
entrypoint: gcloud
images:
- >-
$_AR_HOSTNAME/$_AR_PROJECT_ID/$_AR_REPOSITORY/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
options:
substitutionOption: ALLOW_LOOSE
logging: CLOUD_LOGGING_ONLY
substitutions:
_INSTANCE_CONNECTION_NAME: calcium-verbena-459112-e2:northamerica-northeast1:c-cedille
_DATABASE_PORT: '5432'
_AR_REPOSITORY: cloud-run-source-deploy
_TRIGGER_ID: 6201f5b5-71b7-418b-b278-284b14b2c285
_AR_PROJECT_ID: calcium-verbena-459112-e2
_PLATFORM: managed
_SERVICE_NAME: c-cedille
_DEPLOY_REGION: northamerica-northeast1
_AR_HOSTNAME: northamerica-northeast1-docker.pkg.dev
tags:
- gcp-cloud-build-deploy-cloud-run
- gcp-cloud-build-deploy-cloud-run-managed
- c-cedille
availableSecrets:
secretManager:
- versionName: projects/$PROJECT_ID/secrets/next_public_server_url/versions/latest
env: 'next_public_server_url'
- versionName: projects/$PROJECT_ID/secrets/database_uri/versions/latest
env: 'database_uri'
- versionName: projects/$PROJECT_ID/secrets/payload_secret/versions/latest
env: 'payload_secret'
- versionName: projects/$PROJECT_ID/secrets/cron_secret/versions/latest
env: 'cron_secret'
- versionName: projects/$PROJECT_ID/secrets/preview_secret/versions/latest
env: 'preview_secret'
- versionName: projects/$PROJECT_ID/secrets/gcs_bucket/versions/latest
env: 'gcs_bucket'
- versionName: projects/$PROJECT_ID/secrets/gcs_endpoint/versions/latest
env: 'gcs_endpoint'
- versionName: projects/$PROJECT_ID/secrets/gcs_project_id/versions/latest
env: 'gcs_project_id'
PS: I needed to add a period between the dollar signs ($.$) here because this forum won't allow it.
And the Dockerfile:
FROM node:22-alpine AS base
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
COPY panda.config.ts ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN \
--mount=type=secret,id=next_public_server_url,target=/run/secrets/next_public_server_url \
--mount=type=secret,id=database_uri,target=/run/secrets/database_uri \
--mount=type=secret,id=payload_secret,target=/run/secrets/payload_secret \
--mount=type=secret,id=cron_secret,target=/run/secrets/cron_secret \
--mount=type=secret,id=preview_secret,target=/run/secrets/preview_secret \
--mount=type=secret,id=gcs_bucket,target=/run/secrets/gcs_bucket \
--mount=type=secret,id=gcs_endpoint,target=/run/secrets/gcs_endpoint \
--mount=type=secret,id=gcs_project_id,target=/run/secrets/gcs_project_id \
export NEXT_PUBLIC_SERVER_URL=$(cat /run/secrets/next_public_server_url) && \
export DATABASE_URI=$(cat /run/secrets/database_uri) && \
export PAYLOAD_SECRET=$(cat /run/secrets/payload_secret) && \
export CRON_SECRET=$(cat /run/secrets/cron_secret) && \
export PREVIEW_SECRET=$(cat /run/secrets/preview_secret) && \
export GCS_BUCKET=$(cat /run/secrets/gcs_bucket) && \
export GCS_ENDPOINT=$(cat /run/secrets/gcs_endpoint) && \
export GCS_PROJECT_ID=$(cat /run/secrets/gcs_project_id) && \
if [ -f yarn.lock ]; then yarn run build; \
elif [ -f package-lock.json ]; then npm run build; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
else echo "Lockfile not found." && exit 1; \
fi
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]
As you can see from the logs, the proxy is starting successfully (line 721), but Postgres is unable to connect (line 921):
starting build "a515b436-4e21-4980-bf23-c7a4acd3afa4"
FETCHSOURCE
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
Initialized empty Git repository in /workspace/.git/
From https://github.com/johnboylesingfield/content-website-template
* branch 204503fad47bb939a1035da5fd17994d5b099754 -> FETCH_HEAD
HEAD is now at 204503f Test
GitCommit:
204503fad47bb939a1035da5fd17994d5b099754
BUILD
Starting Step #0 - "Proxy"
Already have image (with digest): gcr.io/cloud-builders/wget
--2025-05-13 03:12:01-- https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.16.0/cloud-sql-proxy.linux.amd64
Resolving storage.googleapis.com (storage.googleapis.com)... 142.251.183.207, 142.251.184.207, 142.250.125.207, ...
Connecting to storage.googleapis.com (storage.googleapis.com)|142.251.183.207|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 34925892 (33M) [application/octet-stream]
Saving to: '/workspace/cloud-sql-proxy'
0K .......... .......... .......... .......... .......... 0% 39.0M 1s
...
34100K ....... 100% 125M=0.3s
2025-05-13 03:12:01 (116 MB/s) - '/workspace/cloud-sql-proxy' saved [34925892/34925892]
Finished Step #0 - "Proxy"
Starting Step #1 - "Build"
Already have image (with digest): gcr.io/cloud-builders/docker
2025/05/13 03:12:02 Authorizing with Application Default Credentials
2025/05/13 03:12:03 [calcium-verbena-459112-e2:northamerica-northeast1:c-cedille] Listening on 127.0.0.1:5432
2025/05/13 03:12:03 The proxy has started successfully and is ready for new connections!
Sending build context to Docker daemon 35.7MB
Step 1/33 : FROM node:22-alpine AS base
22-alpine: Pulling from library/node
f18232174bc9: Already exists
63786652eaff: Pulling fs layer
0c2b42acd277: Pulling fs layer
4509b69886a5: Pulling fs layer
4509b69886a5: Verifying Checksum
0c2b42acd277: Verifying Checksum
0c2b42acd277: Download complete
4509b69886a5: Download complete
63786652eaff: Verifying Checksum
63786652eaff: Download complete
63786652eaff: Pull complete
0c2b42acd277: Pull complete
4509b69886a5: Pull complete
Digest: sha256:ad1aedbcc1b0575074a91ac146d6956476c1f9985994810e4ee02efd932a68fd
Status: Downloaded newer image for node:22-alpine
---> 461edc13e56b
Step 2/33 : FROM base AS deps
---> 461edc13e56b
Step 3/33 : RUN apk add --no-cache libc6-compat
---> Running in 577aa279bf3c
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/community/x86_64/APKINDEX.tar.gz
(1/3) Installing musl-obstack (1.2.3-r2)
(2/3) Installing libucontext (1.3.2-r0)
(3/3) Installing gcompat (1.1.0-r4)
OK: 10 MiB in 20 packages
Removing intermediate container 577aa279bf3c
---> ef33ebe140fc
Step 4/33 : WORKDIR /app
---> Running in 835bd8eff972
Removing intermediate container 835bd8eff972
---> 3c3e55bef8f6
Step 5/33 : COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
---> cee24c35c8c6
Step 6/33 : COPY panda.config.ts ./
---> b7a0a3d69be2
Step 7/33 : RUN if [ -f yarn.lock ]; then yarn --frozen-lockfile; elif [ -f package-lock.json ]; then npm ci; elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; else echo "Lockfile not found." && exit 1; fi
---> Running in 83f3d7e335eb
! Corepack is about to download https://registry.npmjs.org/pnpm/-/pnpm-10.10.0.tgz
! The local project doesn't define a 'packageManager' field. Corepack will now add one referencing pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39.
! For more details about this field, consult the documentation at https://nodejs.org/api/packages.html#packagemanager
Lockfile is up to date, resolution step is skipped
Progress: resolved 1, reused 0, downloaded 0, added 0
Packages: +919
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 919, reused 0, downloaded 14, added 0
Progress: resolved 919, reused 0, downloaded 36, added 8
Progress: resolved 919, reused 0, downloaded 59, added 16
Progress: resolved 919, reused 0, downloaded 117, added 38
Progress: resolved 919, reused 0, downloaded 144, added 46
Progress: resolved 919, reused 0, downloaded 165, added 51
Progress: resolved 919, reused 0, downloaded 166, added 55
Progress: resolved 919, reused 0, downloaded 178, added 55
Progress: resolved 919, reused 0, downloaded 179, added 55
Progress: resolved 919, reused 0, downloaded 180, added 55
Progress: resolved 919, reused 0, downloaded 181, added 55
Progress: resolved 919, reused 0, downloaded 212, added 67
Progress: resolved 919, reused 0, downloaded 287, added 99
Progress: resolved 919, reused 0, downloaded 368, added 140
Progress: resolved 919, reused 0, downloaded 460, added 182
Progress: resolved 919, reused 0, downloaded 493, added 201
Progress: resolved 919, reused 0, downloaded 584, added 244
Progress: resolved 919, reused 0, downloaded 677, added 279
Progress: resolved 919, reused 0, downloaded 780, added 333
Progress: resolved 919, reused 0, downloaded 919, added 438
Progress: resolved 919, reused 0, downloaded 919, added 919, done
.../sharp@0.34.1/node_modules/sharp install$ node install/check
.../sharp@0.32.6/node_modules/sharp install$ (node install/libvips && node install/dll-copy && prebuild-install) || (node install/can-compile && node-gyp rebuild && node install/dll-copy)
.../sharp@0.34.1/node_modules/sharp install: Done
.../sharp@0.32.6/node_modules/sharp install: sharp: Downloading https://github.com/lovell/sharp-libvips/releases/download/v8.14.5/libvips-8.14.5-linuxmusl-x64.tar.br
.../sharp@0.32.6/node_modules/sharp install: sharp: Integrity check passed for linuxmusl-x64
.../sharp@0.32.6/node_modules/sharp install: Done
dependencies:
+ @payloadcms/db-postgres 3.37.0
+ @payloadcms/next 3.37.0
+ @payloadcms/richtext-lexical 3.37.0
+ @payloadcms/storage-gcs 3.37.0
+ @radix-ui/react-popover 1.1.13
+ @radix-ui/react-slot 1.2.2
+ cross-env 7.0.3
+ lucide-react 0.503.0
+ next 15.3.1
+ next-international 1.3.1
+ next-sitemap 4.2.3
+ payload 3.37.0
+ react 19.1.0
+ react-dom 19.1.0
+ sharp 0.32.6
+ slugify 1.6.6
devDependencies:
+ @eslint/eslintrc 3.3.1
+ @pandacss/dev 0.53.6
+ @types/node 20.17.46
+ @types/react 19.1.2
+ @types/react-dom 19.1.2
+ eslint 9.26.0
+ eslint-config-next 15.3.1
+ prettier 3.5.3
+ typescript 5.8.3
╭ Warning ─────────────────────────────────────────────────────────────────────╮
│ │
│ Ignored build scripts: esbuild, unrs-resolver. │
│ Run "pnpm approve-builds" to pick which dependencies should be allowed │
│ to run scripts. │
│ │
╰──────────────────────────────────────────────────────────────────────────────╯
> content-website-template@0.1.0 prepare /app
> panda codegen
`styled-system/css`: the css function to author styles
`styled-system/tokens`: the css variables and js function to query your tokens
`styled-system/patterns`: functions to implement and apply common layout patterns
Done in 26.8s using pnpm v10.10.0
Removing intermediate container 83f3d7e335eb
---> ccf88adb8d6a
Step 8/33 : FROM base AS builder
---> 461edc13e56b
Step 9/33 : WORKDIR /app
---> Running in 9d7330b7d898
Removing intermediate container 9d7330b7d898
---> 95db3dd2edd4
Step 10/33 : COPY --from=deps /app/node_modules ./node_modules
---> a2cca85484cb
Step 11/33 : COPY . .
---> f8d4a0af386b
Step 12/33 : ARG NEXT_PUBLIC_SERVER_URL │ │
---> Running in 966d41965813
Removing intermediate container 966d41965813
---> b128a06297db
Step 13/33 : ARG DATABASE_URI │ │
---> Running in 01fe4264c381
Removing intermediate container 01fe4264c381
---> a693890af855
Step 14/33 : ARG PAYLOAD_SECRET │ │
---> Running in 7e4cc7a22508
Removing intermediate container 7e4cc7a22508
---> d97f8f857155
Step 15/33 : ARG CRON_SECRET │ │
---> Running in 27b6f731a88f
Removing intermediate container 27b6f731a88f
---> 4b650d924211
Step 16/33 : ARG PREVIEW_SECRET │ │
---> Running in d4aa24d12202
Removing intermediate container d4aa24d12202
---> 0489cc593f6a
Step 17/33 : ARG GCS_BUCKET │ │
---> Running in c77c790ce790
Removing intermediate container c77c790ce790
---> 3606bc519a81
Step 18/33 : ARG GCS_ENDPOINT │ │
---> Running in 5e70f019dcdb
Removing intermediate container 5e70f019dcdb
---> f5e21fdf640d
Step 19/33 : ARG GCS_PROJECT_ID
---> Running in 395bae59b21d
Removing intermediate container 395bae59b21d
---> 4d0a6b231d5c
Step 20/33 : RUN export NEXT_PUBLIC_SERVER_URL=${NEXT_PUBLIC_SERVER_URL} && export DATABASE_URI=${DATABASE_URI} && export PAYLOAD_SECRET=${PAYLOAD_SECRET} && export CRON_SECRET=${CRON_SECRET} && export PREVIEW_SECRET=${PREVIEW_SECRET} && export GCS_BUCKET=${GCS_BUCKET} && export GCS_ENDPOINT=${GCS_ENDPOINT} && export GCS_PROJECT_ID=${GCS_PROJECT_ID} && if [ -f yarn.lock ]; then yarn run build; elif [ -f package-lock.json ]; then npm run build; elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; else echo "Lockfile not found." && exit 1; fi
---> Running in 91b54da53136
! Corepack is about to download https://registry.npmjs.org/pnpm/-/pnpm-10.10.0.tgz
! The local project doesn't define a 'packageManager' field. Corepack will now add one referencing pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39.
! For more details about this field, consult the documentation at https://nodejs.org/api/packages.html#packagemanager
> content-website-template@0.1.0 build /app
> pnpm prepare && cross-env NODE_OPTIONS=--no-deprecation next build
> content-website-template@0.1.0 prepare /app
> panda codegen
`styled-system/css`: the css function to author styles
`styled-system/tokens`: the css variables and js function to query your tokens
`styled-system/patterns`: functions to implement and apply common layout patterns
Attention: Next.js now collects completely anonymous telemetry regarding usage.
This information is used to shape Next.js' roadmap and prioritize features.
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
https://nextjs.org/telemetry
▲ Next.js 15.3.1
Creating an optimized production build ...
info [hrtime] Extracted in (196.81ms)
✓ Compiled successfully in 93s
Linting and checking validity of types ...
Collecting page data ...
[03:16:03] ERROR: Error: cannot connect to Postgres. Details: connect ECONNREFUSED 127.0.0.1:5432
err: {
"type": "Error",
"message": "connect ECONNREFUSED 127.0.0.1:5432",
"stack":
Error: connect ECONNREFUSED 127.0.0.1:5432
at /app/.next/server/chunks/2742.js:286:1863
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async lx (/app/.next/server/chunks/2742.js:166:19565)
at async Object.lS [as connect] (/app/.next/server/chunks/2742.js:166:19901)
at async tJ.init (/app/.next/server/chunks/2742.js:33:17302)
at async tX (/app/.next/server/chunks/2742.js:33:20600)
at async Object.v [as generateStaticParams] (/app/.next/server/app/(frontend)/[locale]/[slug]/page.js:1:9031)
at async builtRouteParams (/app/node_modules/.pnpm/next@15.3.1_react-dom@19.1.0_react@19.1.0__react@19.1.0_sass@1.77.4/node_modules/next/dist/build/static-paths/app.js:277:36)
at async buildAppStaticPaths (/app/node_modules/.pnpm/next@15.3.1_react-dom@19.1.0_react@19.1.0__react@19.1.0_sass@1.77.4/node_modules/next/dist/build/static-paths/app.js:247:25)
at async /app/node_modules/.pnpm/next@15.3.1_react-dom@19.1.0_react@19.1.0__react@19.1.0_sass@1.77.4/node_modules/next/dist/build/utils.js:920:79
"errno": -111,
"code": "ECONNREFUSED",
"syscall": "connect",
"address": "127.0.0.1",
"port": 5432
}
⨯ Next.js build worker exited with code: 1 and signal: null
ELIFECYCLE Command failed with exit code 1.
The command '/bin/sh -c export NEXT_PUBLIC_SERVER_URL=${NEXT_PUBLIC_SERVER_URL} && export DATABASE_URI=${DATABASE_URI} && export PAYLOAD_SECRET=${PAYLOAD_SECRET} && export CRON_SECRET=${CRON_SECRET} && export PREVIEW_SECRET=${PREVIEW_SECRET} && export GCS_BUCKET=${GCS_BUCKET} && export GCS_ENDPOINT=${GCS_ENDPOINT} && export GCS_PROJECT_ID=${GCS_PROJECT_ID} && if [ -f yarn.lock ]; then yarn run build; elif [ -f package-lock.json ]; then npm run build; elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; else echo "Lockfile not found." && exit 1; fi' returned a non-zero code: 1
Finished Step #1 - "Build"
ERROR
ERROR: build step 1 "gcr.io/cloud-builders/docker" failed: step exited with non-zero status: 1
A few other notes:
Thanks for your help.