Comprehensive rule set for secure, performant server-side rendering (SSR) across modern JavaScript/TypeScript frameworks.
You've been burned by SSR before. Hydration mismatches, cache invalidation nightmares, security holes, and performance bottlenecks that make you question whether server-side rendering is worth the complexity. These Cursor Rules eliminate the guesswork and dangerous patterns that turn SSR from a performance optimization into a maintenance disaster.
Most SSR implementations fail because developers treat them like client-side apps that happen to run on the server. You end up with:
These rules implement battle-tested SSR patterns used by high-traffic applications. Instead of learning through production incidents, you get enterprise-level security, caching, and performance patterns from day one.
Core Philosophy: SSR only where it provides measurable SEO or first-paint value. Everything else uses static generation or client-side rendering.
The Challenge: Product pages need SEO for search visibility but also real-time inventory and pricing.
The Solution:
// Next.js with ISR + micro-caching
export async function getStaticProps({ params }) {
const product = await fetchProduct(params.id);
return {
props: { product },
revalidate: 300, // ISR every 5 minutes
};
}
// Micro-cache for burst traffic
const productCache = cacheRender(
`product-${productId}`,
2000, // 2-second micro-cache
() => renderProductPage(product)
);
Result: Search engines get fast, SEO-optimized HTML while users see real-time data with sub-100ms response times during traffic spikes.
The Challenge: Personalized content requires SSR for first-paint performance but involves sensitive user data.
The Solution:
// SvelteKit with secure data handling
export async function load({ request, cookies }) {
const session = await validateSession(cookies.get('session'));
if (!session) throw redirect(302, '/login');
// Server-only data fetching
const userData = await fetchUserData(session.userId);
return {
props: {
user: sanitizeUserData(userData), // Never expose sensitive fields
}
};
}
Result: Fast-loading personalized pages with zero sensitive data exposure to the client bundle.
The Challenge: Blog posts and articles need fast loading but don't change frequently.
The Solution:
// Nuxt.js with intelligent caching
export default defineNuxtConfig({
routeRules: {
'/blog/**': {
isr: 3600, // Regenerate hourly
headers: { 'Cache-Control': 's-maxage=3600, stale-while-revalidate=86400' }
},
'/': { prerender: true }, // Static homepage
}
});
Result: Editors publish content that automatically propagates globally within minutes, while readers get instant page loads from edge cache.
Start with this decision tree:
Add these headers to every SSR response:
export const securityHeaders = {
'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline'",
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
};
// Layer 1: Micro-cache (1-10 seconds)
const microCache = new Map<string, { body: string; expires: number }>();
// Layer 2: Edge CDN (60 seconds with stale-while-revalidate)
res.setHeader('Cache-Control', 's-maxage=60, stale-while-revalidate=600');
// Layer 3: Database query cache (Redis, 5 minutes)
const dbCache = await redis.get(`query:${queryHash}`);
// Track SSR render times
const renderStart = performance.now();
const html = await renderPage(props);
const renderTime = performance.now() - renderStart;
// Log structured data for monitoring
console.log(JSON.stringify({
timestamp: Date.now(),
level: 'info',
requestId: req.id,
route: req.path,
ttfb_ms: renderTime,
cache_hit: !!cacheHit,
}));
Next.js: Use App Router with React Server Components for zero-JS data fetching
Nuxt.js: Enable Nitro presets for automatic server optimization
SvelteKit: Implement selective prerendering with prerender = true
Astro: Default to static with minimal JavaScript islands
These rules eliminate the trial-and-error phase of SSR implementation. You get production-proven patterns for security, performance, and maintainability from your first commit.
Copy these rules into your Cursor editor and start building SSR applications that actually deliver on their performance promises. Your users will notice the difference, and your future self will thank you for avoiding the common SSR pitfalls that plague most implementations.
The difference between struggling with SSR complexity and shipping fast, secure server-rendered applications is following patterns that have already solved these problems at scale.
You are an expert in Server-Side Rendering (SSR) with TypeScript, Node.js, React, Vue, Svelte, and edge delivery networks (Cloudflare, Akamai).
Key Principles
- Adopt SSR only where it delivers SEO or first-paint value; prefer SSG or CSR elsewhere.
- Secure every rendered byte: strong CSP, HTTPS-only, output escaping by default.
- Optimise Time-To-First-Byte (TTFB) with micro-caching, streaming, code splitting, and edge caching.
- Keep servers stateless and horizontally scalable; externalise sessions and caches.
- Fail fast: validate inputs early, use early returns, log structured context.
Language-Specific Rules – TypeScript / Node.js
- All source files end with .ts/.tsx; enable strict mode in tsconfig.
- Use async/await exclusively; no .then chains inside async functions.
- Disallow `any`; use `unknown` + type-guard narrowing.
- ESM imports only; one default export per file (except React/Vue/Svelte components).
- Directory names kebab-case; utility files camelCase; components PascalCase.
- Never reference `process.env` in the client bundle; resolve on the server and pass as props.
- Treat functions as pure: no hidden mutations or shared state.
Error Handling and Validation
- Validate request bodies/params with Zod/Yup/Joi; throw `HttpError(400)` on failure.
- Wrap every external call (DB, GraphQL, REST) in try/catch; rethrow sanitised errors.
- Central error middleware returns uniform JSON or renders `_error` pages.
- Apply Helmet or equivalent to set:
• Content-Security-Policy
• Strict-Transport-Security
• X-Content-Type-Options
- Run `npm audit --production --audit-level=high` on every CI build.
Framework-Specific Rules
Next.js
- Use `getServerSideProps` only for highly dynamic pages; otherwise `getStaticProps` + ISR.
- Embrace the `app/` directory and React Server Components; data fetching inside server components only.
- In `middleware.ts`, add edge micro-cache headers: `Cache-Control: s-maxage=1, stale-while-revalidate=59`.
- Use `next/font` for self-hosted fonts.
Nuxt.js
- Enable Nitro server preset for auto isolation.
- Server routes via `defineEventHandler`; validate with `h3`.
- `routeRules` caching example: `{ cache: { swr: 60, maxAge: 300 } }`.
- Separate client/server plugins; avoid DOM APIs in server side.
SvelteKit
- Use `prerender` when possible; SSR pages only for auth or real-time data.
- Implement `handle` hook for CSP + micro-cache with `event.depends`.
Astro
- Default to static output; enable SSR adapter only where needed.
- Keep JavaScript islands minimal; prefer partial hydration.
Remix
- Keep `loader` functions pure; return typed JSON via `json<T>()`.
- Use `defer()` for HTML streaming.
- Provide `CatchBoundary` and `ErrorBoundary` for graceful handling.
Additional Sections
Performance & Caching
- Layered cache:
1. In-memory micro-cache (1–10 s) for burst traffic.
2. Edge CDN with SWR (≈60 s) and geo variation.
3. Redis/object cache for expensive DB queries.
- Use HTTP/2 preload or server push for critical assets.
- Dynamic imports with `webpackPrefetch: true` or Vite `/* @vite-ignore */` hints.
- Lighthouse budget: Perf ≥90 in CI.
Testing
- Snapshot SSR HTML with Jest + Testing Library.
- E2E with Playwright across target browsers.
- Security: weekly OWASP ZAP scan; `snyk test` in pipeline.
Deployment & Ops
- Blue/green or canary with auto-rollback on >1 % error rate.
- Expose `/metrics` for Prometheus; include SSR render time histogram.
- Trace requests with New Relic/Datadog; alert when 95th TTFB >600 ms.
Analytics & Logging
- Inject server-side analytics in the HTML head; client analytics for hydration mismatch.
- Log JSON lines: `{ ts, level, reqId, route, ttfb_ms }`.
SEO & Headers
- Render `canonical`, `hreflang`, `og:*` tags server side.
- Provide dynamic `sitemap.xml` nightly; serve `robots.txt`.
Security Summary
- Run SSR processes as non-root; place behind reverse proxy.
- Rate-limit POST/PUT (e.g., 100/min/IP).
- Sanitize user HTML with DOMPurify before rendering.
Example Micro-Cache (Node.js)
```ts
const microCache = new Map<string, { body: string; expires: number }>();
export async function cacheRender(key: string, ttl = 2000, renderer: () => Promise<string>) {
const now = Date.now();
const hit = microCache.get(key);
if (hit && hit.expires > now) return hit.body;
const html = await renderer();
microCache.set(key, { body: html, expires: now + ttl });
return html;
}
```