This guide outlines the steps required to deploy the StreetEdge monorepo to Google Cloud Platform (GCP) and test it in a live environment.
Before attempting an online deployment, ensure the monorepo is healthy and all packages are correctly linked.
cd streetedge-backend-app
pnpm install
pnpm buildEnsure you have a GCP Project created with the following services enabled via the GCP Console:
- Cloud Run: To host the API (
apps/api) and Dashboard (apps/nextjs). - Artifact Registry: To store your Docker container images.
- Secret Manager: To securely store environment variables (API keys, DB URLs).
- IAM (Identity and Access Management): To manage deployment permissions.
StreetEdge uses GitHub Actions for automated deployment. The skeleton is located at .github/workflows/ci.yml.
This is the secure, keyless method for GitHub to authenticate with GCP. Follow these steps using the gcloud CLI or GCP Console:
This pool will manage the identity relationship between GitHub and GCP.
gcloud iam workload-identity-pools create "github-pool" \
--project="${PROJECT_ID}" \
--location="global" \
--display-name="GitHub Actions Pool"Example: github-pool
This defines the connection to GitHub's identity server. Note: The attribute-condition is required to ensure only your repository can access the pool.
gcloud iam workload-identity-pools providers create-oidc "github-provider" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="github-pool" \
--display-name="GitHub Provider" \
--attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" \
--attribute-condition="assertion.repository == '${GITHUB_REPO}'" \
--issuer-uri="https://token.actions.githubusercontent.com"Example Provider Path: projects/123456789012/locations/global/workloadIdentityPools/github-pool/providers/github-provider
This account will perform the actual deployment actions.
gcloud iam service-accounts create "github-deployer" \
--project="${PROJECT_ID}" \
--display-name="GitHub Actions Deployer"Example: github-deployer@streetedge-prod-123.iam.gserviceaccount.com
Assign roles to the Service Account so it can manage Cloud Run and Artifact Registry.
# Allow deploying to Cloud Run
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:github-deployer@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/run.developer"
# Allow uploading to Artifact Registry
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:github-deployer@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/artifactregistry.writer"
# Allow impersonating the service account (Required for Cloud Run)
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:github-deployer@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/iam.serviceAccountUser"This connects your specific GitHub repository to the Service Account.
gcloud iam service-accounts add-iam-policy-binding "github-deployer@${PROJECT_ID}.iam.gserviceaccount.com" \
--project="${PROJECT_ID}" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/github-pool/attribute.repository/${GITHUB_REPO}"- ${PROJECT_NUMBER}: Found in the GCP Project Dashboard.
- ${GITHUB_REPO}: Format:
owner/repository-name(e.g.,ariefbayu/streetedge-backend-app). Note: Do not include the full URL or.gitsuffix.
Add the following secrets to your GitHub repository settings:
GCP_PROJECT_ID: Your unique GCP project ID.GCP_WORKLOAD_IDENTITY_PROVIDER: The full resource name of your OIDC provider.GCP_SERVICE_ACCOUNT: The email of the deployment service account.
Each service in the apps/ directory requires a Dockerfile. Because we are using a Turborepo monorepo, we use the turbo prune command to create a subset of the monorepo containing only the files needed for a specific service.
- Prune: Run
npx turbo prune @streetedge/[app-name] --dockerto generate an isolatedout/directory. - Build: Use a multi-stage Dockerfile to install dependencies, build the app, and run the production output.
- Optimize: Use slim base images (
node:22-slim) to reduce costs and deployment speed on Cloud Run.
This file should live in streetedge-backend-app/apps/api/Dockerfile.
FROM node:22-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
FROM base AS builder
WORKDIR /app
RUN npm install -g turbo
COPY . .
# Generate a pruned version of the monorepo for the API
RUN turbo prune @streetedge/api-hub --docker
FROM base AS installer
WORKDIR /app
COPY --from=builder /app/out/json/ .
COPY --from=builder /app/out/pnpm-lock.yaml ./pnpm-lock.yaml
RUN pnpm install --frozen-lockfile
COPY --from=builder /app/out/full/ .
RUN pnpm turbo run build --filter=@streetedge/api-hub
FROM base AS runner
WORKDIR /app
COPY --from=installer /app/apps/api/dist ./dist
COPY --from=installer /app/node_modules ./node_modules
COPY --from=installer /app/apps/api/package.json ./package.json
EXPOSE 3001
CMD ["node", "dist/index.js"]This file should live in streetedge-backend-app/apps/nextjs/Dockerfile. Next.js requires the standalone output mode enabled in next.config.js.
# ... (Base, Builder, and Installer stages similar to API above) ...
# Final Runner stage for Next.js
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=installer /app/apps/nextjs/public ./apps/nextjs/public
COPY --from=installer /app/apps/nextjs/.next/standalone ./
COPY --from=installer /app/apps/nextjs/.next/static ./apps/nextjs/.next/static
EXPOSE 3000
CMD ["node", "apps/nextjs/server.js"]Run these commands from the root of the monorepo:
# 1. Authenticate Docker with GCP
gcloud auth configure-docker [REGION]-docker.pkg.dev
# 2. Build the image (example for API)
docker build -t [REGION]-docker.pkg.dev/[PROJECT_ID]/[REPO_NAME]/api-hub:latest -f apps/api/Dockerfile .
# 3. Push the image
docker push [REGION]-docker.pkg.dev/[PROJECT_ID]/[REPO_NAME]/api-hub:latestManage your secrets and configuration variables:
- Local Development: Use
.envfiles within the specific app directories (do not commit these). - Production (GCP): Use GCP Secret Manager to inject sensitive values (e.g.,
DATABASE_URL,FIREBASE_SECRET) into Cloud Run at runtime.
To test a deployment immediately from your local machine using the gcloud CLI:
# Deploy the Ingestion API
cd streetedge-backend-app/apps/api
gcloud run deploy streetedge-api \
--source . \
--platform managed \
--region YOUR_REGION \
--allow-unauthenticated
# Deploy the Next.js Dashboard
cd streetedge-backend-app/apps/nextjs
gcloud run deploy streetedge-dashboard \
--source . \
--platform managed \
--region YOUR_REGION \
--allow-unauthenticatedAssessor: StreetEdge Technical Architect Status: Initial Guide Created (2026-05-06)