The Hospital That Got Hacked

Imagine you're a developer at a hospital. You just shipped a patient portal. It lives at hospital.com/patient-portal. Everything's fine — until one morning, a nurse finds a cross-site scripting bug in the internal scheduling tool, sitting at hospital.com/scheduler.

Here's the terrifying part: because both apps share the same origin, that single XSS vulnerability just handed an attacker access to every patient's session cookie — their medical records, prescription data, all of it. One bug. Total compromise.

That's not a hypothetical. That's what happens when you choose the wrong routing architecture.

This post breaks down one of the most underrated architectural decisions you'll make: subdomains versus path-based routing. I'll show you how banks, hospitals, big tech, and ecommerce companies actually think about it — because this one choice quietly shapes your security, deployment pipeline, scaling strategy, and career.


What Are We Actually Choosing Between?

On the surface, this looks cosmetic. Who cares if it's shop.amazon.com or amazon.com/shop?

Subdomain Routing
https://shop.amazon.com
https://docs.amazon.com
https://aws.amazon.com
🛡️ Each subdomain = its own browser origin
Path Routing
https://amazon.com/shop
https://amazon.com/docs
https://amazon.com/aws
⚠️ All paths share the same browser origin

With subdomain routing, each application gets its own address — its own front door. shop.amazon.com and docs.amazon.com share the parent domain, but the browser treats them as separate origins.

With path routing, everything lives under one roof. One domain, one origin — you carve up apps using URL paths. /shop, /docs, /aws are just rooms inside the same house.

This single decision ripples through six critical dimensions: security, cost, infrastructure, application code, SEO, and authentication. And once you ship with one approach, switching is painful. Let's walk through each one.


1. Security: The Blast Radius Problem

This is the one that matters most. To explain it properly, you need one concept: browser origin policy.

The browser treats each unique combination of protocol, domain, and port as a separate "origin." The key rule: JavaScript running in one origin cannot access cookies, localStorage, or the DOM of another origin. That's the browser's security wall.

Watch what happens with our two approaches.

With subdomainsscheduler.hospital.com and patient.hospital.com are two different origins. If an attacker exploits an XSS vulnerability in the scheduler, they can steal the scheduler's cookies. Bad — but they cannot reach the patient portal's cookies, localStorage, or session data. The damage is contained.

With pathshospital.com/scheduler and hospital.com/patient-portal are the same origin. No wall. That one XSS bug in the scheduler? The attacker now has access to every cookie, every piece of localStorage, every DOM element across every app on the domain. Patient records. Admin panels. Billing data. Everything.

This is what security engineers call the blast radius — how far does damage spread when something goes wrong?

Click the button below to visualize how an XSS attack propagates in each architecture.

🛡️ Subdomain Routing
scheduler.hospital.com
Scheduling App
✦ ORIGIN WALL ✦
patient.hospital.com
Patient Portal
⚠️ Path Routing
hospital.com/scheduler
Scheduling App
— same origin, no wall —
hospital.com/patient-portal
Patient Portal

Real-World Examples

Banking. Chase has secure.chase.com for banking and creditcards.chase.com for credit cards. Wells Fargo runs connect.secure.wellsfargo.com. They don't put their trading platform and mortgage portal on the same origin. If a vulnerability hits one product, regulators ask: "Could this have compromised accounts in your other products?" With path-based routing, the answer is yes — by design.

Ecommerce. Shopify gives every merchant their own subdomain: yourstore.myshopify.com. If every Shopify store shared the same origin, one compromised store could access session data from every other store — affecting millions of merchants.

Healthcare. HIPAA compliance isn't optional. If patient data leaks through a vulnerability in a co-located app that you could have isolated with subdomains, that's an audit finding.

One nuance: Even with subdomains, if you set your auth cookie to Domain=.hospital.com (with the leading dot), that cookie becomes accessible across all subdomains. You still need intentional cookie scoping — but the default posture is isolation, and that's always where you want to start.

Verdict: subdomains win, and it's not close.


2. Cost: The Myth That Subdomains Are Expensive

Many developers avoid subdomains assuming it costs more. Let's bust that myth.

Subdomains are free. If you own yourdomain.com, you can create unlimited subdomains at zero additional cost.

SSL certificates? Let's Encrypt gives you wildcard certificates — one cert covers *.yourdomain.com — for free. Certbot handles per-subdomain certs automatically with auto-renewal.

DNS records? One A record per subdomain. Cloudflare's free tier supports unlimited subdomains with DNS and proxying.

VPS cost? Identical. Whether Nginx routes on subdomain or path, the compute cost is the same.

The actual cost difference between subdomains and paths is effectively zero.

Verdict: it's a tie.


3. Infrastructure & Deployment: Where It Gets Real

This is where the architectural difference becomes tangible, especially at the senior and principal level.

Compare two Nginx configurations side by side.

Subdomain config — each app gets its own server block. Clean and isolated. Changing the marketplace config cannot break the chatbot.

server {
    server_name marketplace.yourdomain.com;
    location / { proxy_pass http://marketplace:3000; }
}

server {
    server_name chatbot.yourdomain.com;
    location / { proxy_pass http://chatbot:4000; }
}

Path config — everything lives in one block with location directives, and you need path rewriting. Your app doesn't know it's mounted at /marketplace — it thinks it's at /. Nginx strips the prefix before forwarding, and that rewriting breaks in subtle ways: nested routes, static assets, API paths — all need to be rewrite-aware.

server {
    server_name yourdomain.com;
    location /marketplace/ {
        rewrite ^/marketplace/(.*)$ /$1 break;
        proxy_pass http://marketplace:3000;
    }
    location /chatbot/ {
        rewrite ^/chatbot/(.*)$ /$1 break;
        proxy_pass http://chatbot:4000;
    }
}

The Deployment Story

It's Friday afternoon. Marketplace has a critical bug fix. With subdomains, you redeploy that one container. The chatbot, LMS, and blog are completely unaffected — different server blocks, different containers, different pipelines.

With paths, you're touching the same Nginx config, the same server block. A bad rewrite rule during the marketplace deploy can take down routing for the chatbot too. Everything is coupled.

Scale and Team Structure

AWS Console lives at console.aws.amazon.com. AWS Documentation at docs.aws.amazon.com. S3 uses s3.console.aws.amazon.com. Each service is owned by a different team, deployed on its own schedule, on its own infrastructure. When the S3 team needs to scale, they don't coordinate with the Lambda team. The subdomain boundary is also an organizational boundary.

Google does the same: mail.google.com, docs.google.com, drive.google.com, calendar.google.com — separate products, separate teams, separate release cycles.

Migration path: if your chatbot becomes wildly popular and needs a dedicated server, with subdomains you change one DNS record — a five-minute operation. With paths, you'd need to refactor your entire routing layer.

Verdict: subdomains win decisively.


4. Application Code: The Hidden Prefix Tax

You don't feel this pain upfront. You feel it six months later when things are subtly broken everywhere.

With subdomains, your React app thinks it lives at /. Routes are clean:

<Route path="/products" component={Products} />
<Route path="/cart" component={Cart} />

API calls are simple: fetch('/api/products'). Every asset reference starts from /. It just works — because from the app's perspective, it is the entire website.

With paths, every app needs to know its mounted prefix. React Router needs a basename:

<BrowserRouter basename="/marketplace">
  <Route path="/products" component={Products} />
</BrowserRouter>

Every API call needs the prefix: fetch('/marketplace/api/products'). Every image tag, stylesheet link, and asset must include the prefix. Miss one? Broken image. Broken route. Broken API call. And these bugs only surface in production, because in development your app IS at root.

I call this the prefix tax — a constant low-grade complexity that every developer on every team has to carry, forever.

Stripe runs dashboard.stripe.com and docs.stripe.com — not stripe.com/dashboard and stripe.com/docs. Their dashboard is a complex React SPA; their docs site is a completely different static site generator. Forcing both into the same origin with path prefixes would create constant friction for both teams.

Verdict: subdomains win.


5. SEO and Auth: Where Paths Fight Back

In fairness, path-based routing has a genuine edge in two areas.

SEO: Domain Authority

Google treats subdomains as semi-separate websites. A backlink to blog.yourdomain.com strengthens your blog subdomain, but that authority doesn't fully flow to shop.yourdomain.com. With paths, every backlink to yourdomain.com/anything strengthens the same root domain.

For content-heavy businesses — media companies, content marketing sites — this matters. If organic search is your primary growth channel, paths consolidate authority faster.

The nuance: Google has gotten much better at associating subdomains with their parent. Companies like HubSpot run blog.hubspot.com and still dominate search. Google Search Console lets you explicitly link your subdomains. It's manageable — but paths do have a natural advantage.

Auth: Zero Configuration Overhead

With paths, authentication is trivially simple. Everything is the same origin — set a cookie and every app reads it. No CORS. No cookie tricks.

With subdomains, you need two things:

  1. Set your auth cookie with Domain=.yourdomain.com so it's shared across subdomains.
  2. Configure CORS so that marketplace.yourdomain.com can make credentialed requests to auth.yourdomain.com.

About 15 lines of config — not hard, but extra work, and if you get it wrong your login flow breaks.

Paths win on SEO and auth simplicity. Worth acknowledging.

But notice the pattern: paths win on convenience; subdomains win on isolation and scalability. In production systems serving real users with real data, convenience takes a back seat to resilience.


6. The Enterprise Pattern: Use Both

What do companies actually do in practice? They use both.

The answer isn't "always subdomains" or "always paths." It's: subdomains between applications, paths within them.

GitHub: gist.github.com and docs.github.com are separate products → subdomains. Inside github.com, /pulls, /issues, and /settings are features of one product → paths.

AWS: console.aws.amazon.com and docs.aws.amazon.com are separate products → subdomains. Inside the console, /s3, /ec2, /lambda are sections of one UI → paths.

This hybrid maps cleanly to a concept from Domain-Driven Design: bounded contexts. Each subdomain is a self-contained business capability with its own models, data, and team. Within that context, paths organize the internal features.

Subdomain per app         →  Bounded Context
Nginx reverse proxy       →  API Gateway
Shared auth service       →  Identity Provider (Okta, Auth0)
Docker network            →  Service Mesh

If you can explain this architecture in a system design interview and connect it to enterprise equivalents, you're demonstrating principal-engineer-level thinking. Not because of the tooling — because you understood why the boundaries exist.


Quick Verdict Scorecard

Dimension Subdomains Paths
🔒 Security WINS
💰 Cost TIE TIE
🚀 Infrastructure & Deployment WINS
⚙️ App Code Simplicity WINS
📈 SEO WINS
🔑 Auth Simplicity WINS

The Decision Framework

Use Paths When

You're building one application with multiple pages. Settings, profile, dashboard — these are features of the same product, built by the same team, deployed together.

/settings /dashboard /profile
Use Subdomains When

You're building multiple applications — different codebases, tech stacks, or deployment cycles. Or when security isolation matters, which is basically always in production.

shop.domain.com api.domain.com
At Scale: The Hybrid

Subdomains between apps, paths within each app. GitHub, AWS, and Google all use this pattern in practice.

shop.amazon.com/products/detail

The routing choice you make today echoes through your system's security posture, your team's deployment velocity, and your platform's ability to scale. It's one of those decisions that feels small but compounds over time.

Pick intentionally.