If you are building an early-stage multi-tenant SaaS, start with path slugs unless you already have a strong reason to give every tenant a separate hostname.
For a restaurant ordering app, that means something like:
order.in/{restaurant}/menu
order.in/{restaurant}/table/{token}
order.in/{restaurant}/kitchen
order.in/{restaurant}/admin
This is usually easier to build, test, deploy, and debug than starting with:
restaurant.order.in
restaurant2.order.in
The important part is not choosing slugs forever. The important part is centralizing tenant resolution from day one, so your app can support path slugs now, tenant subdomains later, and custom domains when customers actually ask for them.
Quick Answer
Use a path slug first when:
- You are still validating the product.
- You have only a few early tenants.
- Most traffic comes from QR codes, direct links, or logged-in users.
- You do not need strong tenant branding in the hostname yet.
- You want simpler local development and deployment.
Move toward subdomains when:
- Tenant identity should be visible before the path.
- Tenants care about branded links.
- You plan to support customer custom domains.
- You need cleaner cookie or session boundaries.
- Public sharing and URL appearance matter to the business.
Do not make subdomains the default just because other SaaS products use them. Many of those products adopted subdomains after their tenant lifecycle became more mature.
Decision Table
| Choice | Best for | Watch out for |
|---|---|---|
| Path slug | Early products, QR flows, simple deployments | Do not scatter slug parsing everywhere. |
| Tenant subdomain | Branded tenant URLs and cleaner tenant-level routing | Plan wildcard DNS, SSL, and support workflows. |
| Custom domain | Customers who need their own branded hostname | Requires verification, status tracking, and lifecycle management. |
Why This Question Comes Up
The question usually appears when a founder or small product team has moved past a prototype and starts thinking about scale.
At first, the product has one customer, one admin panel, and one menu page. A path slug feels obvious:
- One domain.
- One deployment.
- One set of routing rules.
- One place to debug.
Then the team notices that many SaaS products use tenant subdomains:
acme.example.comteam.example.comrestaurant.example.com
That creates a reasonable worry: “If we start with slugs, are we making a bad long-term architecture decision?”
Usually, no.
Starting with slugs is fine as long as tenant lookup is not scattered everywhere in the codebase. The mistake is not choosing slugs. The mistake is hard-coding tenant parsing in controllers, components, database queries, analytics events, and background jobs until changing the URL model becomes painful.
The Restaurant Ordering Example
Imagine a QR-based restaurant ordering product.
A diner scans a table QR code and opens:
order.in/sushi-house/table/12
The kitchen team uses:
order.in/sushi-house/kitchen
The manager uses:
order.in/sushi-house/admin
At this stage, the restaurant probably cares about whether the menu opens quickly, whether orders reach the kitchen, and whether the admin panel is usable. They probably do not care deeply whether the URL is:
order.in/sushi-house/menu
or:
sushi-house.order.in/menu
If the main user journey starts with a QR code at the table, the user is not typing the URL manually. That makes path slugs a very reasonable first version.
Why Slugs Are Usually Better Early
Path slugs reduce the number of moving parts.
You do not need wildcard DNS on day one. You do not need tenant-aware local hostname setup. You do not need extra certificate logic. You do not need to explain to every new teammate how tenant subdomain routing works before the product has proven demand.
The practical advantages are simple:
- Easier routing.
- Easier local development.
- Easier preview environments.
- Easier debugging.
- Easier customer support.
- Fewer DNS and SSL edge cases.
For an early-stage product, that matters. You want engineering attention on product behavior, not infrastructure shape.
When Subdomains Start Making Sense
Subdomains become more attractive when the tenant identity itself becomes part of the product experience.
That can happen when restaurants start sharing links publicly:
sushi-house.order.in/menu
It can also happen when the tenant wants a more branded entry point:
menu.sushihouse.com
At that point, subdomains are no longer just a routing preference. They become part of tenant onboarding, brand presentation, support, analytics, and operations.
Subdomains are especially useful when:
- Tenant URLs are visible in ads, receipts, signs, emails, or social posts.
- Customers expect a branded URL.
- You want a future path toward custom domains.
- Tenant-level cookies or sessions should be separated.
- You want clearer operational ownership for each tenant entry.
But even then, you do not need to rewrite the whole product if you planned the tenant lookup layer well.
The Architecture That Keeps Both Options Open
The best early decision is to create one place in the app that answers this question:
Which tenant is this request for?
That function or middleware might be called:
resolveTenant(request)
It should hide the URL pattern from the rest of the app.
function resolveTenant(request) {
const host = request.headers.host;
const path = new URL(request.url).pathname;
if (isCustomDomain(host)) {
return findTenantByCustomDomain(host);
}
if (isTenantSubdomain(host)) {
return findTenantBySubdomain(host);
}
return findTenantBySlug(path);
}
The rest of your application should not care whether the tenant came from a slug, subdomain, or custom domain. It should receive a tenant object and continue.
This gives you a clean migration path:
- Start with path slug.
- Add tenant subdomain support later.
- Add custom domain support when the business needs it.
That is the real goal: not choosing the perfect URL pattern today, but avoiding a corner that is hard to leave later.
A Simple Tenant Mapping Table
You can support this with a plain mapping model.
tenant_id
slug
subdomain
custom_domain
status
verification_status
default_destination
created_at
updated_at
last_seen_at
For an early product, many of these fields can be empty. The point is to make the tenant entry explicit.
A restaurant might start as:
slug: sushi-house
subdomain: null
custom_domain: null
status: active
Later, it can become:
slug: sushi-house
subdomain: sushi-house
custom_domain: menu.sushihouse.com
status: active
The restaurant identity remains the same. Only the entry method evolves.
What About SEO?
For a QR-based restaurant ordering app, SEO is probably not the first decision driver.
If users reach the menu by scanning a table QR code, then search ranking matters less than reliability, speed, and correct tenant resolution.
SEO becomes more important when:
- Restaurant menu pages are public and indexed.
- Restaurant pages should rank in local search.
- Tenants publish links on their own websites.
- You want each tenant page to have a clear canonical URL.
In that case, decide whether tenant pages should benefit from the main domain:
order.in/sushi-house/menu
or live as more separate hostnames:
sushi-house.order.in/menu
There is no universal answer. The right answer depends on whether tenant pages are public content assets or mostly operational app screens.
What About Performance and Scale?
Slug versus subdomain rarely decides performance by itself.
Performance usually depends more on:
- Database tenant indexes.
- Cache keys.
- CDN behavior.
- Backend routing.
- Query design.
- How table tokens and sessions are validated.
- How much work happens on every request.
A subdomain is not automatically more scalable than a slug. A slug is not automatically slower than a subdomain.
If you centralize tenant resolution and keep the lookup cheap, both patterns can scale.
What About Tenant Isolation?
Subdomains can help with browser-level boundaries, especially around cookies and sessions. But they do not create full tenant isolation by themselves.
Real tenant isolation comes from:
- Correct database scoping.
- Tenant-aware authorization.
- Separate roles and permissions.
- Careful cache separation.
- Safe admin workflows.
- Clear audit logs.
If a request resolves to the wrong tenant in your backend, a subdomain will not save you. The tenant model and authorization layer matter more than the URL shape.
Common Mistakes to Avoid
The first mistake is spreading slug parsing everywhere.
If every route, component, and query extracts the restaurant slug differently, future subdomain support becomes a rewrite.
The second mistake is mixing tenant identity with table identity.
For example:
order.in/sushi-house/table/12
Here, sushi-house identifies the tenant. table/12 identifies a resource inside that tenant. Keep those concepts separate.
The third mistake is building a custom domain system before anyone needs it.
Custom domains require verification, DNS instructions, SSL status, error states, and support workflows. It is fine to design for them later. It is usually not necessary to build the whole thing before your first restaurant is live.
The fourth mistake is not having an entry lifecycle.
Eventually, each tenant entry needs answers:
- Who owns this entry?
- Where does it point?
- Is it active?
- When was it changed?
- Who changed it?
- Should it be retired?
A Practical Recommendation
For the restaurant ordering app described above, I would use this plan:
Stage 1: Start With Slugs
Use:
order.in/{restaurant}/menu
order.in/{restaurant}/table/{token}
order.in/{restaurant}/kitchen
order.in/{restaurant}/admin
Keep it simple. Validate the product. Make sure restaurants can onboard, customers can order, and the kitchen flow works.
Stage 2: Centralize Tenant Resolution
Add one tenant resolution layer that every request passes through.
Do not let each page decide how to parse the restaurant identity. One middleware or function should do that job.
Stage 3: Add Subdomains When Branding Matters
When restaurants start asking for cleaner or more branded URLs, support:
sushi-house.order.in/menu
This should be an additional entry method, not a second product architecture.
Stage 4: Add Custom Domains When Customers Demand Them
When restaurants want:
menu.sushihouse.com
you will need a domain verification and routing workflow. By then, you will know whether the demand is real and what support problems appear most often.
Key Takeaways
- Start with slugs if the product is early.
- Do not copy subdomains just because mature SaaS products use them.
- Centralize tenant resolution from day one.
- Treat tenant URLs as lifecycle objects, not just route patterns.
- Add subdomains when branding, public sharing, cookies, or custom domains make them useful.
- Add custom domains only when the product and customer base justify the operational work.
FAQ
Is the slug approach fine long-term?
Yes, it can be. Many products keep slugs for a long time. The issue is not whether slugs are valid. The issue is whether tenant resolution is cleanly designed.
Are subdomains faster or more scalable?
Not automatically. Subdomains can help with some routing and browser-boundary concerns, but performance usually depends on database design, caching, request handling, and tenant lookup efficiency.
Will slugs hurt SEO?
Not necessarily. For QR-based restaurant ordering, SEO may not be the main concern. If tenant pages need to rank publicly, think carefully about canonical URLs, indexed content, and whether tenant pages should live under the main domain or separate hostnames.
Will starting with slugs make custom domains harder later?
Only if slug parsing is scattered across the codebase. If you centralize tenant resolution, adding subdomains and custom domains later is much more realistic.
When should I switch from slugs to subdomains?
Switch when tenant identity in the hostname creates real value: stronger branding, public sharing, custom domain preparation, cleaner tenant boundaries, or clearer routing operations.
Final Thought
The question is not really “slug or subdomain forever?”
The better question is:
Can your product resolve a tenant from different entry patterns without rewriting the app?
If the answer is yes, you can start simple and grow into the more advanced URL model when the business actually needs it.