Learn

Navigate through learn topics

Server-Side vs Client-Side Components, SSR Best Practices and Secure Fetching with RLS

Understanding server-side and client-side components, secure data fetching with RLS and scaling SSR for large databases

Last updated: 8/15/2025

This guide explains the differences between server-side and client-side components, how to combine them effectively, how to secure client-side data fetching with Row-Level Security (RLS) and best practices for scaling Server-Side Rendering (SSR) with large databases.

1. Server-Side vs Client-Side Components

  • Server-side components
    • Run on the server before sending HTML to the browser.
    • Ideal for SEO, secure data fetching and fast initial load times.
  • Client-side components
    • Run in the browser after the page loads.
    • Handle interactivity and dynamic updates without a full page reload.
  • Hybrid approach
    • Modern frameworks (e.g., Next.js, Remix, Nuxt) combine both: server-side for initial rendering, client-side for user interaction.

2. Using Both in One Application

A common hybrid workflow:

  1. Server renders HTML with initial data.
  2. Browser hydrates interactive components with JavaScript.
  3. Client fetches additional data on demand (e.g., via fetch()).

Example: A product page

  • Server-side: fetches product details from a database and renders HTML.
  • Client-side: handles "Add to Cart" clicks and updates the UI instantly without reloading.

3. Secure Client-Side Fetching with RLS

  • Client-side fetching can be secure if API-level restrictions (such as Row-Level Security) strictly control data access.
  • Risks:
    • Requests are visible in browser DevTools.
    • Never embed API keys in frontend code.
  • Best practices:
    1. Require authentication for sensitive data.
    2. Apply RLS to scope queries to the authenticated user or tenant.
    3. Never rely on client-side filtering alone.
    4. Use short-lived tokens.
    5. Rate-limit and log all sensitive queries.

4. SSR with Large Databases

When scaling SSR for large datasets:

  • Query only what you need — avoid SELECT *.
  • Index properly — ensure indexes match your WHERE + ORDER BY.
  • Use keyset/cursor pagination instead of OFFSET.
  • Cache at multiple layers — Redis for query results, CDN/edge for public HTML.
  • Read replicas for heavy read workloads; connection pooling to prevent overload.
  • Partition large tables by date, tenant, or logical grouping.
  • Stream SSR output to deliver above-the-fold content as soon as possible.

5. Three Common SSR Page Types

  1. List pages (large collections)

    • Composite index on filter/sort columns.
    • Keyset paginate 20–50 items per request.
    • Cache query results for 30–60s in Redis; edge-cache HTML if public.
  2. Detail pages

    • Fetch by primary key plus a small related set.
    • Cache for 2–5 minutes with tag-based invalidation.
  3. Personal dashboards

    • Multiple small queries in parallel using a connection pool.
    • Short-TTL Redis cache per widget; no public edge cache for private data.

6. Operational Playbook

  • Connection pooling (e.g., pgBouncer, pgpool) to reuse DB connections.
  • Read replicas for distributing read queries.
  • Backpressure with query timeouts and circuit breakers.
  • Online migrations for large tables to avoid downtime.
  • Partitioning for very large tables.
  • Data TTL policies to archive old rows and keep active datasets small.

7. Pitfalls to Avoid

  • Offset pagination on huge tables.
  • Rendering massive lists without proper pagination.
  • Using SELECT * in SSR.
  • Missing covering indexes for frequent queries.
  • Publicly caching private or user-specific pages.
  • Blocking SSR for slow assets instead of streaming.

8. Quick Checklist

  • Queries return only the fields required for rendering.
  • Keyset pagination for large lists.
  • Indexes match WHERE and ORDER BY patterns.
  • Read replicas and pooling in place.
  • Redis cache with short TTL and stampede protection.
  • SSR streams above-the-fold first.
  • Least-privilege DB roles; secrets stored server-side only.
  • Tenant scoping and optional RLS enforced.
  • Monitoring for slow queries, cache hit rates and replica lag.

Related Topics

Learn more about security and data protection: