Heavy Dashboards
For queue-heavy dashboards that run expensive row + summary RPCs (for example posts review):- Keep the route page server-only for auth, permissions, and canonical URL normalization.
- Move the actual table + summary fetch into a client shell with TanStack Query.
- Fetch through
@tuturuuu/internal-apihelpers, not ad-hoc client fetch calls. - Avoid
router.refresh()for routine list refreshes; prefer query refetch/invalidation.
Builder Migration Pattern (Education Module Groups)
For highly interactive editors (for example the course builder with module groups + drag/drop):- Keep the route page as a thin server-side auth/permission gate.
- Move list data loading into a client shell backed by React Query.
- Use
@tuturuuu/internal-apihelpers as the client fetch boundary (listWorkspaceCourseModuleGroups,listWorkspaceCourseModules, and reorder helpers). - Avoid
router.refresh()for routine drag/drop updates; mutate via API and invalidate the corresponding query keys. - When a drag/drop move changes both membership and order, await the membership mutation before firing any follow-up reorder mutations, and invalidate only the affected query keys instead of every list in the builder.
- Keep create/update payload contracts explicit (
module_group_idis required for new course modules).
Strategy Preference Order
Choose the earliest applicable strategy:- Pure Server Component (RSC) - Read-only, cacheable, SEO-critical data
- Server Action - Mutations returning updated state to RSC
- RSC + Client Hydration - When background refresh needed
- React Query (Client-Side) - Interactive, rapidly changing state
- Realtime Subscriptions - Live updates materially improve UX
1. Pure Server Component (RSC)
When to Use
✅ Best For:- Initial page load data
- SEO-critical content
- Rarely changing data
- Read-only operations
- Database queries that don’t need real-time updates
- Interactive forms
- Frequent updates
- Client-side state
- Real-time data
Implementation
Caching Strategy
Loading States
Error Handling
2. Server Actions
When to Use
✅ Best For:- Form submissions
- Mutations with server-side validation
- Operations requiring auth checks
- Redirects after mutations
- Progressive enhancement
- Read operations (use RSC instead)
- Complex client-side state management
- Real-time updates
Implementation
Client Usage
3. RSC + Client Hydration
When to Use
✅ Best For:- Initial server render with client updates
- Data that changes frequently
- Combining SEO with interactivity
- Background refresh patterns
Implementation
4. React Query (Client-Side)
When to Use
✅ Best For:- Interactive dashboards
- Rapidly changing data
- Complex client-side state
- Optimistic updates
- Automatic background refetching
- SEO-critical content
- Initial page load (prefer RSC)
Implementation with tRPC
Query Key Conventions
Use stable array query keys:Thin Server Gate + Client Query Shell
For dense dashboard surfaces that need URL-driven filtering, pagination, and frequent background refreshes, prefer a thin server gate plus a client query shell:- Keep the route page server-side only for auth, permission checks, redirects, and metadata.
- Move interactive data loading into client hooks backed by TanStack Query.
- Back those hooks with workspace-scoped Internal API helpers instead of ad hoc
fetch('/api/...')calls. - Store queryable UI state such as
page,pageSize,q,sortBy, andpathinnuqs. - Invalidate query keys after mutations instead of relying on
router.refresh().
Optimistic Updates
Cache Invalidation
5. Realtime Subscriptions
When to Use
✅ Best For:- Collaborative features
- Chat applications
- Live dashboards
- Multiplayer features
- Notification systems
- Infrequent updates
- Static content
- SEO-critical data
Implementation
React Query Guidelines
Query Configuration
Prefetching
Parallel Queries
Dependent Queries
Decision Matrix
| Use Case | Strategy | Why |
|---|---|---|
| Blog posts | RSC | SEO, rarely changes |
| Task list (initial load) | RSC | Fast initial render |
| Create task form | Server Action | Mutation, redirect |
| Dashboard metrics | React Query | Frequent updates |
| Real-time chat | Realtime Subscription | Collaboration |
| Task toggle | React Query (optimistic) | Interactive, instant feedback |
| User profile (view) | RSC | Rarely changes |
| User profile (edit) | Server Action | Mutation with validation |
| Workspace members | RSC + hydration | SEO + background refresh |
| Live notifications | Realtime Subscription | Real-time updates critical |
Best Practices
✅ DO
-
Start with RSC
-
Use specific query keys
-
Set appropriate staleTime
-
Implement optimistic updates for better UX
-
Invalidate narrowly
❌ DON’T
-
Don’t use client fetching for SEO content
-
Don’t skip staleTime
-
Don’t invalidate globally
-
Don’t use Realtime for infrequent updates