Server-Side Rendering (SSR)
Saucebase supports optional server-side rendering (SSR) with Inertia.js, allowing you to control SSR on a per-page basis. Use SSR for public pages that need SEO, and skip it for authenticated pages for better performance.
How SSR Works in Saucebase
Saucebase uses a two-level SSR control system:
- Boot level (config): SSR server runs continuously
- Request level (middleware): SSR disabled by default for each request
- Response level (macros): Controllers opt-in with
->withSSR()or opt-out with->withoutSSR()
SSR is disabled by default via middleware. Controllers must explicitly opt-in with ->withSSR() to enable it for specific pages.
Configuration
Enable SSR Server
The SSR server must be enabled in configuration:
'ssr' => [
'enabled' => (bool) env('INERTIA_SSR_ENABLED', true),
'url' => env('INERTIA_SSR_URL', 'http://127.0.0.1:13714'),
],
INERTIA_SSR_ENABLED=true
INERTIA_SSR_URL=http://127.0.0.1:13714
Middleware Configuration
The HandleInertiaRequests middleware disables SSR by default:
public function handle(Request $request, Closure $next): Response
{
// Disable SSR by default for all requests
Config::set('inertia.ssr.enabled', false);
return parent::handle($request, $next);
}
This ensures SSR is opt-in rather than opt-out.
Using SSR in Controllers
Enable SSR for a Page
Use the ->withSSR() macro to enable SSR for public pages:
use Inertia\Inertia;
class HomeController extends Controller
{
public function index()
{
return Inertia::render('Index')
->with('products', Product::featured()->get())
->withSSR(); // ✅ Enable SSR for SEO
}
}
Explicitly Disable SSR
Use ->withoutSSR() to ensure SSR is disabled:
class DashboardController extends Controller
{
public function index()
{
return Inertia::render('Dashboard')
->with('stats', $this->getUserStats())
->withoutSSR(); // ✅ Explicitly disable SSR
}
}
Default Behavior (No Macro)
If you don't use a macro, SSR is disabled (middleware default):
class AboutController extends Controller
{
public function index()
{
return Inertia::render('About');
// SSR disabled (middleware default)
}
}
When to Use SSR
✅ Enable SSR For:
Public Pages Needing SEO
- Landing pages
- Product listings
- Blog posts
- Marketing pages
- Documentation
Social Media Sharing
- Pages with Open Graph meta tags
- Pages shared on Twitter, Facebook, LinkedIn
Performance Benefits
- Faster First Contentful Paint (FCP)
- Improved Largest Contentful Paint (LCP)
- Better Core Web Vitals scores
❌ Disable SSR For:
Authenticated Pages
- Dashboards
- Admin panels
- User settings
- Private content
Real-Time Data
- Pages that update frequently
- Pages with real-time subscriptions
- Live data dashboards
Performance Optimization
- Reduce server load
- Skip unnecessary rendering
Example: E-Commerce Site
class ProductController extends Controller
{
// Public product listing - Enable SSR for SEO
public function index()
{
return Inertia::render('Products/Index')
->with('products', Product::paginate(20))
->withSSR();
}
// Public product detail - Enable SSR for SEO
public function show(Product $product)
{
return Inertia::render('Products/Show')
->with('product', $product->load('images', 'reviews'))
->withSSR();
}
// Admin product edit - Disable SSR (authenticated)
public function edit(Product $product)
{
return Inertia::render('Products/Edit')
->with('product', $product)
->withoutSSR();
}
}
Starting the SSR Server
Development
Start the SSR server manually:
php artisan inertia:start-ssr
Or run in background:
php artisan inertia:start-ssr &
The composer dev command automatically starts the SSR server for you!
Production
Use a process manager like Supervisor to keep the SSR server running:
[program:inertia-ssr]
process_name=%(program_name)s
command=php /path/to/your/app/artisan inertia:start-ssr
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/inertia-ssr.log
Reload Supervisor:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start inertia-ssr
Verifying SSR
View Page Source
The easiest way to verify SSR is working:
- Visit a page with SSR enabled
- Right-click → "View Page Source" (Ctrl+U / Cmd+Option+U)
- Look for rendered content inside
<div id="app" data-page="...">
SSR Enabled:
<div id="app" data-page="{...}">
<div class="container">
<h1>Welcome to Saucebase</h1>
<p>Full HTML content here...</p>
</div>
</div>
SSR Disabled:
<div id="app" data-page="{...}"></div>
<!-- Empty div, content rendered client-side -->
Check Response Headers
curl -I https://localhost/
SSR responses typically have larger Content-Length.
Browser DevTools
- Open Network tab
- Reload page
- Click on the document request
- Check "Preview" or "Response" tab
- Look for rendered HTML content
Troubleshooting
SSR Server Not Starting
Symptoms: Error when starting SSR server
Solution:
# Check if port is in use
lsof -i :13714
# Kill existing process
kill -9 <PID>
# Restart SSR server
php artisan inertia:start-ssr
SSR Not Working
Checklist:
- ✅ SSR server is running
- ✅
INERTIA_SSR_ENABLED=truein.env - ✅ Controller uses
->withSSR() - ✅ Frontend assets built:
npm run build
Debug:
# Check SSR server status
curl http://127.0.0.1:13714
# Expected response: Node.js SSR server info
Memory Issues
Symptoms: SSR server crashes or becomes slow
Solution:
Increase Node.js memory limit:
# In production startup script
NODE_OPTIONS=--max-old-space-size=4096 php artisan inertia:start-ssr
Update Supervisor config:
environment=NODE_OPTIONS="--max-old-space-size=4096"
Hydration Mismatch
Symptoms: Console warning about hydration mismatch
Causes:
- Different data between server and client
- Date/time formatting differences
- Random values in components
Solution:
Ensure consistent data:
// ✅ Good: Consistent timestamp
return Inertia::render('Index')
->with('timestamp', now()->toIso8601String());
// ❌ Bad: Different on server vs client
// Using Date.now() in component
Advanced: Conditional SSR
Enable SSR based on user agent (e.g., only for search bots):
public function index(Request $request)
{
$isBot = Str::contains(
$request->userAgent(),
['bot', 'spider', 'crawler']
);
$response = Inertia::render('Index')
->with('products', Product::all());
return $isBot ? $response->withSSR() : $response;
}
Performance Comparison
Client-Side Rendering (CSR)
Pros:
- ✅ Lower server load
- ✅ Faster subsequent navigations
- ✅ Better for real-time data
Cons:
- ❌ Slower First Contentful Paint
- ❌ Poor SEO (content not in HTML)
- ❌ Bad social media previews
Server-Side Rendering (SSR)
Pros:
- ✅ Fast First Contentful Paint
- ✅ Great for SEO
- ✅ Perfect social media previews
- ✅ Better Core Web Vitals
Cons:
- ❌ Higher server load
- ❌ Increased complexity
- ❌ Potential hydration issues
Best Practices
- Enable SSR selectively - Only for pages that need SEO
- Monitor performance - Track SSR server resource usage
- Use caching - Cache SSR responses when possible
- Test thoroughly - Verify both SSR and CSR work correctly
- Handle errors gracefully - Fallback to CSR if SSR fails
Configuration Flexibility
The macros work with any middleware default:
Current Setup (Recommended)
SSR server enabled, disabled by default via middleware:
// Middleware: Config::set('inertia.ssr.enabled', false)
return Inertia::render('Index')->withSSR(); // Opt-in
return Inertia::render('Dashboard'); // No SSR
Alternative Setup
SSR server enabled, enabled by default:
// Remove Config::set line from middleware
return Inertia::render('Index'); // SSR enabled
return Inertia::render('Dashboard')->withoutSSR(); // Opt-out
The default-disabled approach is recommended to avoid accidentally enabling SSR for authenticated pages.
Technical Implementation
Entry Point Files
Saucebase uses two separate entry points for SSR:
resources/js/app.ts- Client-side rendering entry pointresources/js/ssr.ts- Server-side rendering entry point
Both files initialize the Vue app with Inertia.js, but the SSR entry point includes server-specific configuration.
Macro Registration
The ->withSSR() and ->withoutSSR() macros are registered in:
app/Providers/MacroServiceProvider.php
This provider centralizes all framework macro extensions, making them easy to discover and maintain.
See the Directory Structure page for more details on Saucebase-specific files.
Next Steps
- Routing - Learn about routing with Ziggy
- Modules - Module page resolution with namespace syntax
- Dark & Light Mode - Theme customization and switching
- Testing Guide - Test SSR with Playwright helpers
SSR in Saucebase gives you the best of both worlds: SEO-friendly public pages and fast, dynamic authenticated experiences.