← Workspace Index

Cloud Run Deployment

Deploying Nostra Server (API) as a Stateless Container

1 Prepare the Dockerfile

Critical: Local Libraries

Because we use a local SDK via .yalc, simply copying `package.json` isn't enough. We must copy the hidden .yalc folder into the container.

nostra-server/api/Dockerfile
FROM node:20-alpine

WORKDIR /app

# 1. Copy Manifests and Local Libs
COPY package.json yarn.lock ./
COPY .yalc ./.yalc

# 2. Install Dependencies (Frozen for stability)
RUN yarn install --frozen-lockfile

# 3. Copy Source Code
COPY . .

# 4. Generate Prisma Client (Required for DB access)
RUN npx prisma generate

# 5. Build TypeScript code
RUN yarn build

# 6. Configure Environment
ENV NODE_ENV=production
ENV PORT=8080

# 7. Start
CMD ["node", "dist/index.js"]

2 Build & Push Image

Google Cloud Run needs to pull the image from a registry usually Google Artifact Registry (GAR).

Prerequisite: Ensure you have the `gcloud` CLI installed and authenticated (`gcloud auth login`).
Terminal Command
# 1. Set your Project ID
export PROJECT_ID="your-gcp-project-id"

# 2. Enable Artifact Registry API (First time only)
gcloud services enable artifactregistry.googleapis.com

# 3. Create a Docker Repository (First time only)
gcloud artifacts repositories create nostra-repo \
    --repository-format=docker \
    --location=us-central1 \
    --description="Nostra Docker Repository"

# 4. Configure Docker to use gcloud credentials
gcloud auth configure-docker us-central1-docker.pkg.dev

# 5. Build and Push (Submitting build to Cloud Build is easiest)
# Run this from /nostra-server/api directory
gcloud builds submit --tag us-central1-docker.pkg.dev/$PROJECT_ID/nostra-repo/nostra-api:latest .

Using gcloud builds submit is easier than building locally because it avoids architecture issues (e.g., building on Apple Silicon M1/M2 for Linux servers).

3 Deploy Service

We need to tell Cloud Run about our database. The safest way is using the Cloud SQL Proxy integration.

Deploy Command
gcloud run deploy nostra-api \
  --image us-central1-docker.pkg.dev/$PROJECT_ID/nostra-repo/nostra-api:latest \
  --platform managed \
  --region us-central1 \
  --allow-unauthenticated \
  --set-env-vars="NODE_ENV=production" \
  --set-secrets="DATABASE_URL=projects/$PROJECT_ID/secrets/DB_URL/versions/1"
  • --allow-unauthenticated: Makes the API public (remove this if it's internal only).
  • --set-secrets: Use Google Secret Manager for the `DATABASE_URL` to avoid leaking passwords.

4 Web Server (Next.js) Deployment

Critical: Next.js Standalone

For efficient Docker images, we use Next.js standalone mode. We also need to copy the .yalc folder here as well.

nostra-server/web/next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: "standalone",
  // ... other config
};
module.exports = nextConfig;
nostra-server/web/Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app

# 1. Copy Manifests and Local Libs
COPY package.json yarn.lock ./
COPY .yalc ./.yalc

# 2. Install Dependencies
RUN yarn install --frozen-lockfile

# 3. Copy Source
COPY . .

# 4. Build (Creates .next/standalone)
RUN yarn build

# --- Runner Stage (Small Image) ---
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=8080

# 5. Copy Standalone Build
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public

EXPOSE 8080
CMD ["node", "server.js"]
Build & Deploy Web
# 1. Build Web Image
gcloud builds submit --tag us-central1-docker.pkg.dev/$PROJECT_ID/nostra-repo/nostra-web:latest .

# 2. Deploy Web Service
gcloud run deploy nostra-web \
  --image us-central1-docker.pkg.dev/$PROJECT_ID/nostra-repo/nostra-web:latest \
  --platform managed \
  --region us-central1 \
  --allow-unauthenticated \
  --set-env-vars="NEXT_PUBLIC_API_URL=https://nostra-api-uc.a.run.app"

Note: Set NEXT_PUBLIC_API_URL to the URL of your deployed API service (from Step 3).