How We Served Multiple React Apps from a Single Domain Using GCP Load Balancer, Cloud Storage, and…
Most React deployment tutorials stop at:
How We Served Multiple React Apps from a Single Domain Using GCP Load Balancer, Cloud Storage, and Cloud Run

Most React deployment tutorials stop at:
- Build your React app
- Upload it to a Cloud Storage bucket
- Connect a domain
That works for simple websites, but production applications often need much more:
- Multiple frontend applications under the same domain
- SPA routing support
- Deep links that don’t return 404s
- Social media previews for dynamic pages
- Bot-specific rendering for WhatsApp, Twitter, LinkedIn, Slack, and Facebook
In this article, I’ll show how we built a scalable frontend architecture on Google Cloud Platform that serves multiple React applications behind a single domain while supporting dynamic metadata generation for social sharing.
Architecture Overview
We use:
- Google Cloud Storage for static frontend hosting
- Global HTTP(S) Load Balancer for routing
- Cloud Run for metadata generation
- Custom route rules for SPA support
- Custom error response for over writing 404 response on every dynamic route to 200
Traffic enters through a single load balancer:
User Request ↓ Global Load Balancer ├── Project 1 Bucket ├── Project 2 Bucket └── Cloud Run Metadata Service
The Problem
Deploying 2 or more frontend applications:
Example: we have two projects one as website and other as store front where users purchase products
Landing Website
Used for:
- Marketing pages
- Landing pages
- Documentation
- Public content
- Blogs
Store Application
Used for:
- Analytics
- Product Collection
- User profiles
- Posts
- product recommendations
Both applications needed to live under the same domain.
Why Cloud Storage?
React builds are static assets.
Instead of running Nginx or a VM, we host them in Cloud Storage buckets:
Bucket 1:
website-bucket
Bucket 2:
store-bucket
Benefits:
- Near-zero maintenance
- Automatic scalability
- Extremely low cost
- No server patching
- No container management
Steps to setup a multi-project React frontend under single domain
This guide explains how to create an external HTTP(S) Load Balancer on a reserved global static IP, enable HTTP → HTTPS redirection, Cloud CDN caching, and path‑based routing to multiple Cloud Storage backend buckets.
It is split into two complete approaches:
- Using GCP Console (UI)
- Using CLI (gcloud + gsutil) (coming soon)
Architecture Overview
- Load Balancer: External HTTP(S)
- IP Address: Reserved global static IP
- Protocols: HTTP (80), HTTPS (443)
- Redirect: HTTP → HTTPS (301)
- Backends (GCS):
bucket-website→/bucket-store→/<stotre-routes>/*- Caching: Cloud CDN enabled
Using GCP Console (UI)
Step 1: Create Cloud Storage Buckets
Navigate to:
Cloud Storage → Buckets
Create two buckets:
BucketPurposewebsite-bucketMarketing website, landing pages, blogs, documentationstore-bucketStore application, products, collections, user profiles, posts
Upload your React production build files into the corresponding buckets.
For both buckets:
- Enable public access to objects
- Grant Storage Object Viewer access to
allUsers
This allows the load balancer to serve static assets directly from Cloud Storage.
Step 2: Create Backend Buckets
Navigate to:
Network Services → Load Balancing
Create a new:
External HTTP(S) Load Balancer
Under backend configuration create:
Website Backend
Name
website-backend
Bucket
website-bucket
Optional:
Enable Cloud CDN
Store Backend
Name
store-backend
Bucket
store-bucket
Optional:
Enable Cloud CDN
At this stage both frontend applications are available as independent backend buckets.

Step 3: Configure URL Routing
The load balancer determines which application should receive incoming requests.
Set:
defaultService: website-backend
This means every request is routed to the website by default.
Next, create routing rules for store-related paths:
- prefixMatch: /route1
- prefixMatch: /route2
- prefixMatch: /route3
- prefixMatch: /route4
- prefixMatch: /docs
Route these paths to:
service: store-backend
Now both React applications can share the same domain while remaining independently deployable.
Example

example.com/
→ website-bucket
example.com/blog
→ website-bucket
example.com/product/123
→ store-bucket
example.com/profile/john
→ store-bucket
Step 4: Configure SPA Route Handling
One of the biggest challenges with React applications hosted on Cloud Storage is browser refresh behavior.
Consider:
https://example.com/product/123
When a user refreshes the page:
- Browser requests
/product/123 - Cloud Storage looks for a file named
/product/123 - File doesn’t exist
- Cloud Storage returns
404
To solve this, configure a custom error response policy.
For the website bucket:
customErrorResponsePolicy:
errorResponseRules:
- matchResponseCodes:
- "404"
overrideResponseCode: 200
path: /index.html
Repeat the same configuration for the store bucket.
Now every unknown route loads:
index.html
allowing React Router to handle routing on the client side.
Benefits
- Deep linking
- Browser refresh support
- Shareable URLs
- Better user experience
Step 5: Configure Bot-Aware Metadata Routing
Single Page Applications introduce another challenge.
When a product URL is shared on:
- Twitter / X
- Slack
- Telegram
these platforms don’t execute React.
Instead they fetch the raw HTML response and look for Open Graph tags:
<meta property="og:title">
<meta property="og:image">
<meta property="og:description">
Since React generates these values client-side, social platforms often display empty or incomplete previews.
To solve this problem, create a Cloud Run service that generates metadata dynamically.
The load balancer can inspect the User-Agent header and route crawler traffic differently.
Example:
- matchRules:
- headerMatches:
- headerName: user-agent
prefixMatch: WhatsApp
prefixMatch: /product/
service: metadata-service
Create similar rules for:
Twitterbot
Slackbot
TelegramBot
LinkedInBot
facebookexternalhit
Facebot
Request Flow
Normal User:
User
↓
Load Balancer
↓
store-bucket
↓
React Application
Social Bot:
WhatsApp / Twitter / Facebook Bot
↓
Load Balancer
↓
Cloud Run Metadata Service
↓
Dynamic Open Graph Response
This allows rich previews to appear automatically when links are shared.
Step 6: Configure HTTPS
Reserve a Global Static IP:
VPC Network → IP Addresses
Create a Google-managed SSL certificate and attach your domain.
Example:
example.com
www.example.com
Enable:
HTTP → HTTPS Redirect
Response Code:
301 Permanent Redirect
This ensures all traffic uses HTTPS.
Step 7: Update DNS
Point your domain’s A record to the reserved Global Static IP address.
After DNS propagation and SSL certificate provisioning complete, your architecture will look like:
Internet
│
▼
Global HTTP(S) Load Balancer
│
┌───────────────────┼───────────────────┐
│ │ │
▼ ▼ ▼
website-bucket store-bucket Cloud Run
Metadata
Service
Final Result
✅ Multiple React applications on a single domain
✅ Static hosting using Cloud Storage
✅ Global HTTPS Load Balancer
✅ SPA routing without 404 errors
✅ Independent frontend deployments
✅ Dynamic social media previews
✅ Optional Cloud CDN support
✅ No VMs or Nginx servers to manage
In the next section, we’ll configure the same architecture using gcloud and gsutil, making the entire infrastructure reproducible and automation-friendly.
메타데이터
- post_id
- 273ea1657fa5
- slug
- how-we-served-multiple-react-apps-from-a-single-domain-using-gcp-load-balancer-cloud-storage-and-273ea1657fa5
- url
- https://medium.com/@sashankbhardwaj99/how-we-served-multiple-react-apps-from-a-single-domain-using-gcp-load-balancer-cloud-storage-and-273ea1657fa5
- canonical_url
- https://medium.com/@sashankbhardwaj99/how-we-served-multiple-react-apps-from-a-single-domain-using-gcp-load-balancer-cloud-storage-and-273ea1657fa5
- author_url
- https://medium.com/@sashankbhardwaj99
- status
- ok
- fetched_at
- 2026-06-26 03:39:16