Part 1: The SEO Logic (The "Why")
In the eyes of Google, the root domain (domain.com) is the primary source of authority.
1. "Link Equity" belongs to the Content
Your blog is your "SEO Magnet." Itβs what people link to, share on social media, and cite in research. If your blog is at domain.com, all that link juice flows directly to your root domain. If your app is at app.domain.com, it is technically a separate "bucket."
By putting the blog at the root, your marketing site becomes an authority powerhouse, making it easier for new articles to rank.
2. Cleaning up the "Search Intent"
Google likes to categorize sites.
- Root Domain (
domain.com): High-quality, long-form content, public-facing information. - Subdomain (
app.domain.com): Functional, authenticated, private user data.
By separating them, you ensure that search engine crawlers don't get confused by "private" app pages (like login screens or dashboards) that have no SEO value, keeping your crawl budget focused on your high-value blog posts.
3. Asset and Cookie Isolation
Running your app on a subdomain allows you to keep the "heavy" tracking scripts (Facebook Pixel, GTM, etc.) on the marketing site without slowing down the authenticated app experience. It also provides a security layer by isolating session cookies to the app. subdomain.
Part 2: How to do it in Rails (The "How")
You can handle this in one of two ways: within a single Rails app (using constraints) or via two separate apps.
Strategy A: One App, Two "Sides"
You can use Rails Routing Constraints to serve different views depending on the subdomain.
1. Create a Routing Constraint
# lib/app_constraint.rb
class AppConstraint
def self.matches?(request)
request.subdomain == 'app'
end
end
class BlogConstraint
def self.matches?(request)
request.subdomain.blank? || request.subdomain == 'www'
end
end
2. Configure your routes.rb
Rails.application.routes.draw do
# 1. The Main App (app.domain.com)
constraints AppConstraint do
root to: "dashboards#show", as: :app_root
resources :projects
resources :settings
end
# 2. The Marketing/Blog Side (domain.com)
constraints BlogConstraint do
root to: "marketing#index"
get "features", to: "marketing#features"
# Blog routes
resources :posts, path: 'blog', only: [:index, :show]
end
end
Part 3: The Cookie Trap (Crucial!)
If your app is on app.domain.com and your blog is on domain.com, you probably still want the "Login" button on the blog to know if the user is already signed in. To do this, you must allow cookies to be shared across subdomains.
In your session store configuration:
# config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store,
key: '_your_app_session',
domain: :all, # This allows app.domain.com and domain.com to share the cookie
tld_length: 2
Part 4: The "Pro" Alternative (Reverse Proxy)
Many top-tier companies actually run their blog on a separate system (like Ghost, WordPress, or a static Astro site) but want it to appear inside the Rails app.
If you want your blog at domain.com/blog while the app is at domain.com, you use a Reverse Proxy (via Cloudflare Workers or Nginx).
- Request for
domain.com/blog-> Proxy sends request to a cheap Ghost/WordPress host. - Request for everything else -> Proxy sends request to your Rails App.
Why do this? It gives your marketing team total freedom to change the blog without ever touching your Rails production code.
Summary
- Blog at Root: Maximizes SEO authority and keeps content front-and-center.
- App at Subdomain: Provides a clean, fast, and secure functional environment.
- Use Rails Constraints: If you want to keep everything in one repo.
- Set
domain: :all: So your users stay logged in as they move between the "Content" and the "Product."
Are you struggling with subdomains in your local development? Let me know in the comments and I'll show you how to set up lvh.me! π
Top comments (0)