@jgamaraalv/ts-dev-kit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/.claude-plugin/marketplace.json +24 -0
  2. package/.claude-plugin/plugin.json +24 -0
  3. package/CHANGELOG.md +24 -0
  4. package/LICENSE +21 -0
  5. package/README.md +128 -0
  6. package/agents/accessibility-pro.md +139 -0
  7. package/agents/api-builder.md +110 -0
  8. package/agents/code-reviewer.md +190 -0
  9. package/agents/database-expert.md +138 -0
  10. package/agents/debugger.md +241 -0
  11. package/agents/docker-expert.md +51 -0
  12. package/agents/multi-agent-coordinator.md +378 -0
  13. package/agents/nextjs-expert.md +136 -0
  14. package/agents/performance-engineer.md +138 -0
  15. package/agents/playwright-expert.md +126 -0
  16. package/agents/react-specialist.md +97 -0
  17. package/agents/security-scanner.md +105 -0
  18. package/agents/test-generator.md +221 -0
  19. package/agents/typescript-pro.md +253 -0
  20. package/agents/ux-optimizer.md +93 -0
  21. package/docs/rules/orchestration.md.template +126 -0
  22. package/package.json +28 -0
  23. package/skills/bullmq/SKILL.md +225 -0
  24. package/skills/bullmq/references/flows-and-schedulers.md +186 -0
  25. package/skills/bullmq/references/job-types-and-options.md +163 -0
  26. package/skills/bullmq/references/patterns.md +273 -0
  27. package/skills/bullmq/references/production.md +308 -0
  28. package/skills/composition-patterns/SKILL.md +58 -0
  29. package/skills/composition-patterns/references/architecture-avoid-boolean-props.md +87 -0
  30. package/skills/composition-patterns/references/architecture-compound-components.md +107 -0
  31. package/skills/composition-patterns/references/patterns-children-over-render-props.md +77 -0
  32. package/skills/composition-patterns/references/patterns-explicit-variants.md +87 -0
  33. package/skills/composition-patterns/references/react19-no-forwardref.md +37 -0
  34. package/skills/composition-patterns/references/state-context-interface.md +194 -0
  35. package/skills/composition-patterns/references/state-decouple-implementation.md +96 -0
  36. package/skills/composition-patterns/references/state-lift-state.md +126 -0
  37. package/skills/conventional-commits/SKILL.md +148 -0
  38. package/skills/docker/SKILL.md +55 -0
  39. package/skills/docker/references/compose-configs.md +95 -0
  40. package/skills/docker/references/monorepo-dockerfile.md +111 -0
  41. package/skills/drizzle-pg/SKILL.md +202 -0
  42. package/skills/drizzle-pg/references/advanced.md +299 -0
  43. package/skills/drizzle-pg/references/migrations.md +214 -0
  44. package/skills/drizzle-pg/references/queries.md +321 -0
  45. package/skills/drizzle-pg/references/relations.md +272 -0
  46. package/skills/drizzle-pg/references/schema-pg.md +256 -0
  47. package/skills/drizzle-pg/references/sql-operator.md +215 -0
  48. package/skills/fastify-best-practices/SKILL.md +143 -0
  49. package/skills/fastify-best-practices/references/hooks-and-lifecycle.md +122 -0
  50. package/skills/fastify-best-practices/references/plugins-and-encapsulation.md +137 -0
  51. package/skills/fastify-best-practices/references/request-reply-errors.md +189 -0
  52. package/skills/fastify-best-practices/references/routes-and-handlers.md +134 -0
  53. package/skills/fastify-best-practices/references/server-and-options.md +127 -0
  54. package/skills/fastify-best-practices/references/typescript-and-logging.md +223 -0
  55. package/skills/fastify-best-practices/references/validation-and-serialization.md +190 -0
  56. package/skills/ioredis/SKILL.md +51 -0
  57. package/skills/ioredis/references/advanced-patterns.md +312 -0
  58. package/skills/ioredis/references/cluster-sentinel.md +280 -0
  59. package/skills/ioredis/references/connection-options.md +187 -0
  60. package/skills/ioredis/references/core-api.md +179 -0
  61. package/skills/nextjs-best-practices/SKILL.md +194 -0
  62. package/skills/nextjs-best-practices/references/async-patterns.md +84 -0
  63. package/skills/nextjs-best-practices/references/bundling.md +192 -0
  64. package/skills/nextjs-best-practices/references/data-patterns.md +310 -0
  65. package/skills/nextjs-best-practices/references/debug-tricks.md +127 -0
  66. package/skills/nextjs-best-practices/references/directives.md +74 -0
  67. package/skills/nextjs-best-practices/references/error-handling.md +237 -0
  68. package/skills/nextjs-best-practices/references/file-conventions.md +152 -0
  69. package/skills/nextjs-best-practices/references/font.md +175 -0
  70. package/skills/nextjs-best-practices/references/functions.md +116 -0
  71. package/skills/nextjs-best-practices/references/hydration-error.md +86 -0
  72. package/skills/nextjs-best-practices/references/image.md +184 -0
  73. package/skills/nextjs-best-practices/references/metadata.md +305 -0
  74. package/skills/nextjs-best-practices/references/parallel-routes.md +299 -0
  75. package/skills/nextjs-best-practices/references/route-handlers.md +154 -0
  76. package/skills/nextjs-best-practices/references/rsc-boundaries.md +168 -0
  77. package/skills/nextjs-best-practices/references/runtime-selection.md +40 -0
  78. package/skills/nextjs-best-practices/references/scripts.md +148 -0
  79. package/skills/nextjs-best-practices/references/self-hosting.md +210 -0
  80. package/skills/nextjs-best-practices/references/suspense-boundaries.md +67 -0
  81. package/skills/owasp-security-review/SKILL.md +98 -0
  82. package/skills/owasp-security-review/references/a01-broken-access-control.md +78 -0
  83. package/skills/owasp-security-review/references/a02-security-misconfiguration.md +81 -0
  84. package/skills/owasp-security-review/references/a03-supply-chain-failures.md +65 -0
  85. package/skills/owasp-security-review/references/a04-cryptographic-failures.md +82 -0
  86. package/skills/owasp-security-review/references/a05-injection.md +106 -0
  87. package/skills/owasp-security-review/references/a06-insecure-design.md +76 -0
  88. package/skills/owasp-security-review/references/a07-authentication-failures.md +83 -0
  89. package/skills/owasp-security-review/references/a08-integrity-failures.md +72 -0
  90. package/skills/owasp-security-review/references/a09-logging-alerting-failures.md +76 -0
  91. package/skills/owasp-security-review/references/a10-exceptional-conditions.md +131 -0
  92. package/skills/postgresql/SKILL.md +50 -0
  93. package/skills/postgresql/references/ddl-schema.md +300 -0
  94. package/skills/postgresql/references/indexes.md +257 -0
  95. package/skills/postgresql/references/jsonb.md +261 -0
  96. package/skills/postgresql/references/performance.md +291 -0
  97. package/skills/postgresql/references/psql-cli.md +153 -0
  98. package/skills/postgresql/references/queries.md +287 -0
  99. package/skills/postgresql/references/transactions.md +280 -0
  100. package/skills/react-best-practices/SKILL.md +110 -0
  101. package/skills/react-best-practices/references/advanced-patterns.md +91 -0
  102. package/skills/react-best-practices/references/async-patterns.md +233 -0
  103. package/skills/react-best-practices/references/bundle-optimization.md +201 -0
  104. package/skills/react-best-practices/references/client-patterns.md +178 -0
  105. package/skills/react-best-practices/references/js-performance.md +210 -0
  106. package/skills/react-best-practices/references/rendering-performance.md +209 -0
  107. package/skills/react-best-practices/references/rerender-optimization.md +316 -0
  108. package/skills/react-best-practices/references/server-performance.md +274 -0
  109. package/skills/service-worker/SKILL.md +195 -0
  110. package/skills/service-worker/references/api-reference.md +114 -0
  111. package/skills/service-worker/references/caching-strategies.md +202 -0
  112. package/skills/service-worker/references/push-and-sync.md +261 -0
  113. package/skills/typescript-conventions/SKILL.md +51 -0
  114. package/skills/ui-ux-guidelines/SKILL.md +105 -0
  115. package/skills/ui-ux-guidelines/references/accessibility-and-interaction.md +74 -0
  116. package/skills/ui-ux-guidelines/references/forms-content-checklist.md +126 -0
  117. package/skills/ui-ux-guidelines/references/layout-typography-animation.md +95 -0
@@ -0,0 +1,316 @@
1
+ # Re-render Optimization
2
+
3
+ Reduce unnecessary React re-renders through better state management and memoization.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Defer State Reads to Usage Point](#defer-state-reads-to-usage-point)
8
+ - [Narrow Effect Dependencies](#narrow-effect-dependencies)
9
+ - [Calculate Derived State During Rendering](#calculate-derived-state-during-rendering)
10
+ - [Use Functional setState Updates](#use-functional-setstate-updates)
11
+ - [Hoist Default Non-primitive Props](#hoist-default-non-primitive-props)
12
+ - [Extract to Memoized Components](#extract-to-memoized-components)
13
+ - [Put Interaction Logic in Event Handlers](#put-interaction-logic-in-event-handlers)
14
+ - [Use useRef for Transient Values](#use-useref-for-transient-values)
15
+
16
+ ---
17
+
18
+ ## Defer State Reads to Usage Point
19
+
20
+ Don't subscribe to dynamic state (searchParams, localStorage) if you only read it inside callbacks.
21
+
22
+ **Incorrect (subscribes to all searchParams changes):**
23
+
24
+ ```tsx
25
+ function ShareButton({ chatId }: { chatId: string }) {
26
+ const searchParams = useSearchParams();
27
+
28
+ const handleShare = () => {
29
+ const ref = searchParams.get("ref");
30
+ shareChat(chatId, { ref });
31
+ };
32
+
33
+ return <button onClick={handleShare}>Share</button>;
34
+ }
35
+ ```
36
+
37
+ **Correct (reads on demand, no subscription):**
38
+
39
+ ```tsx
40
+ function ShareButton({ chatId }: { chatId: string }) {
41
+ const handleShare = () => {
42
+ const params = new URLSearchParams(window.location.search);
43
+ const ref = params.get("ref");
44
+ shareChat(chatId, { ref });
45
+ };
46
+
47
+ return <button onClick={handleShare}>Share</button>;
48
+ }
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Narrow Effect Dependencies
54
+
55
+ Specify primitive dependencies instead of objects to minimize effect re-runs.
56
+
57
+ **Incorrect (re-runs on any user field change):**
58
+
59
+ ```tsx
60
+ useEffect(() => {
61
+ console.log(user.id);
62
+ }, [user]);
63
+ ```
64
+
65
+ **Correct (re-runs only when id changes):**
66
+
67
+ ```tsx
68
+ useEffect(() => {
69
+ console.log(user.id);
70
+ }, [user.id]);
71
+ ```
72
+
73
+ **For derived state, compute outside effect:**
74
+
75
+ ```tsx
76
+ // Incorrect: runs on width=767, 766, 765...
77
+ useEffect(() => {
78
+ if (width < 768) enableMobileMode();
79
+ }, [width]);
80
+
81
+ // Correct: runs only on boolean transition
82
+ const isMobile = width < 768;
83
+ useEffect(() => {
84
+ if (isMobile) enableMobileMode();
85
+ }, [isMobile]);
86
+ ```
87
+
88
+ ---
89
+
90
+ ## Calculate Derived State During Rendering
91
+
92
+ If a value can be computed from current props/state, do not store it in state or update it in an effect. Derive it during render.
93
+
94
+ **Incorrect (redundant state and effect):**
95
+
96
+ ```tsx
97
+ function Form() {
98
+ const [firstName, setFirstName] = useState("First");
99
+ const [lastName, setLastName] = useState("Last");
100
+ const [fullName, setFullName] = useState("");
101
+
102
+ useEffect(() => {
103
+ setFullName(firstName + " " + lastName);
104
+ }, [firstName, lastName]);
105
+
106
+ return <p>{fullName}</p>;
107
+ }
108
+ ```
109
+
110
+ **Correct (derive during render):**
111
+
112
+ ```tsx
113
+ function Form() {
114
+ const [firstName, setFirstName] = useState("First");
115
+ const [lastName, setLastName] = useState("Last");
116
+ const fullName = firstName + " " + lastName;
117
+
118
+ return <p>{fullName}</p>;
119
+ }
120
+ ```
121
+
122
+ Reference: [You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect)
123
+
124
+ ---
125
+
126
+ ## Use Functional setState Updates
127
+
128
+ When updating state based on the current state value, use the functional update form. This prevents stale closures, eliminates unnecessary dependencies, and creates stable callback references.
129
+
130
+ **Incorrect (requires state as dependency):**
131
+
132
+ ```tsx
133
+ function TodoList() {
134
+ const [items, setItems] = useState(initialItems);
135
+
136
+ const addItems = useCallback(
137
+ (newItems: Item[]) => {
138
+ setItems([...items, ...newItems]);
139
+ },
140
+ [items], // Recreated on every items change
141
+ );
142
+
143
+ return <ItemsEditor items={items} onAdd={addItems} />;
144
+ }
145
+ ```
146
+
147
+ **Correct (stable callbacks, no stale closures):**
148
+
149
+ ```tsx
150
+ function TodoList() {
151
+ const [items, setItems] = useState(initialItems);
152
+
153
+ const addItems = useCallback((newItems: Item[]) => {
154
+ setItems((curr) => [...curr, ...newItems]);
155
+ }, []); // No dependencies needed
156
+
157
+ const removeItem = useCallback((id: string) => {
158
+ setItems((curr) => curr.filter((item) => item.id !== id));
159
+ }, []); // Safe and stable
160
+
161
+ return <ItemsEditor items={items} onAdd={addItems} onRemove={removeItem} />;
162
+ }
163
+ ```
164
+
165
+ **When to use:** Any setState depending on current state, inside useCallback/useMemo, event handlers, async operations. **When direct updates are fine:** Setting state to a static value (`setCount(0)`), setting from props/arguments only.
166
+
167
+ **Note:** React Compiler can optimize some cases automatically, but functional updates are still recommended for correctness.
168
+
169
+ ---
170
+
171
+ ## Hoist Default Non-primitive Props
172
+
173
+ When memoized components have default non-primitive parameter values, new instances are created on every re-render, breaking memoization.
174
+
175
+ **Incorrect (`onClick` has different values on every rerender):**
176
+
177
+ ```tsx
178
+ const UserAvatar = memo(function UserAvatar({ onClick = () => {} }: { onClick?: () => void }) {
179
+ // ...
180
+ });
181
+ ```
182
+
183
+ **Correct (stable default value):**
184
+
185
+ ```tsx
186
+ const NOOP = () => {};
187
+
188
+ const UserAvatar = memo(function UserAvatar({ onClick = NOOP }: { onClick?: () => void }) {
189
+ // ...
190
+ });
191
+ ```
192
+
193
+ ---
194
+
195
+ ## Extract to Memoized Components
196
+
197
+ Extract expensive work into memoized components to enable early returns before computation.
198
+
199
+ **Incorrect (computes avatar even when loading):**
200
+
201
+ ```tsx
202
+ function Profile({ user, loading }: Props) {
203
+ const avatar = useMemo(() => {
204
+ const id = computeAvatarId(user);
205
+ return <Avatar id={id} />;
206
+ }, [user]);
207
+
208
+ if (loading) return <Skeleton />;
209
+ return <div>{avatar}</div>;
210
+ }
211
+ ```
212
+
213
+ **Correct (skips computation when loading):**
214
+
215
+ ```tsx
216
+ const UserAvatar = memo(function UserAvatar({ user }: { user: User }) {
217
+ const id = useMemo(() => computeAvatarId(user), [user]);
218
+ return <Avatar id={id} />;
219
+ });
220
+
221
+ function Profile({ user, loading }: Props) {
222
+ if (loading) return <Skeleton />;
223
+ return (
224
+ <div>
225
+ <UserAvatar user={user} />
226
+ </div>
227
+ );
228
+ }
229
+ ```
230
+
231
+ **Note:** React Compiler automatically optimizes re-renders, making manual `memo()`/`useMemo()` unnecessary.
232
+
233
+ ---
234
+
235
+ ## Put Interaction Logic in Event Handlers
236
+
237
+ If a side effect is triggered by a specific user action (submit, click, drag), run it in that event handler. Do not model the action as state + effect.
238
+
239
+ **Incorrect (event modeled as state + effect):**
240
+
241
+ ```tsx
242
+ function Form() {
243
+ const [submitted, setSubmitted] = useState(false);
244
+ const theme = useContext(ThemeContext);
245
+
246
+ useEffect(() => {
247
+ if (submitted) {
248
+ post("/api/register");
249
+ showToast("Registered", theme);
250
+ }
251
+ }, [submitted, theme]);
252
+
253
+ return <button onClick={() => setSubmitted(true)}>Submit</button>;
254
+ }
255
+ ```
256
+
257
+ **Correct (do it in the handler):**
258
+
259
+ ```tsx
260
+ function Form() {
261
+ const theme = useContext(ThemeContext);
262
+
263
+ function handleSubmit() {
264
+ post("/api/register");
265
+ showToast("Registered", theme);
266
+ }
267
+
268
+ return <button onClick={handleSubmit}>Submit</button>;
269
+ }
270
+ ```
271
+
272
+ Reference: [Should this code move to an event handler?](https://react.dev/learn/removing-effect-dependencies#should-this-code-move-to-an-event-handler)
273
+
274
+ ---
275
+
276
+ ## Use useRef for Transient Values
277
+
278
+ When a value changes frequently and you don't want a re-render on every update (mouse trackers, intervals, transient flags), store it in `useRef` instead of `useState`.
279
+
280
+ **Incorrect (renders every update):**
281
+
282
+ ```tsx
283
+ function Tracker() {
284
+ const [lastX, setLastX] = useState(0);
285
+
286
+ useEffect(() => {
287
+ const onMove = (e: MouseEvent) => setLastX(e.clientX);
288
+ window.addEventListener("mousemove", onMove);
289
+ return () => window.removeEventListener("mousemove", onMove);
290
+ }, []);
291
+
292
+ return <div style={{ position: "fixed", top: 0, left: lastX, width: 8, height: 8 }} />;
293
+ }
294
+ ```
295
+
296
+ **Correct (no re-render for tracking):**
297
+
298
+ ```tsx
299
+ function Tracker() {
300
+ const lastXRef = useRef(0);
301
+ const dotRef = useRef<HTMLDivElement>(null);
302
+
303
+ useEffect(() => {
304
+ const onMove = (e: MouseEvent) => {
305
+ lastXRef.current = e.clientX;
306
+ if (dotRef.current) {
307
+ dotRef.current.style.transform = `translateX(${e.clientX}px)`;
308
+ }
309
+ };
310
+ window.addEventListener("mousemove", onMove);
311
+ return () => window.removeEventListener("mousemove", onMove);
312
+ }, []);
313
+
314
+ return <div ref={dotRef} style={{ position: "fixed", top: 0, width: 8, height: 8 }} />;
315
+ }
316
+ ```
@@ -0,0 +1,274 @@
1
+ # Server-Side Performance
2
+
3
+ Optimize RSC data fetching, caching, and serialization.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Use after() for Non-Blocking Operations](#use-after-for-non-blocking-operations)
8
+ - [Authenticate Server Actions](#authenticate-server-actions)
9
+ - [Cross-Request LRU Caching](#cross-request-lru-caching)
10
+ - [Per-Request Deduplication with React.cache()](#per-request-deduplication-with-reactcache)
11
+ - [Avoid Duplicate Serialization in RSC Props](#avoid-duplicate-serialization-in-rsc-props)
12
+ - [Parallel Data Fetching with Component Composition](#parallel-data-fetching-with-component-composition)
13
+ - [Minimize Serialization at RSC Boundaries](#minimize-serialization-at-rsc-boundaries)
14
+
15
+ ---
16
+
17
+ ## Use after() for Non-Blocking Operations
18
+
19
+ Use Next.js's `after()` to schedule work that should execute after a response is sent. Prevents logging, analytics, and other side effects from blocking the response.
20
+
21
+ **Incorrect (blocks response):**
22
+
23
+ ```tsx
24
+ export async function POST(request: Request) {
25
+ await updateDatabase(request);
26
+ const userAgent = request.headers.get("user-agent") || "unknown";
27
+ await logUserAction({ userAgent }); // Blocks response
28
+ return new Response(JSON.stringify({ status: "success" }));
29
+ }
30
+ ```
31
+
32
+ **Correct (non-blocking):**
33
+
34
+ ```tsx
35
+ import { after } from "next/server";
36
+ import { headers, cookies } from "next/headers";
37
+
38
+ export async function POST(request: Request) {
39
+ await updateDatabase(request);
40
+
41
+ after(async () => {
42
+ const userAgent = (await headers()).get("user-agent") || "unknown";
43
+ const sessionCookie = (await cookies()).get("session-id")?.value || "anonymous";
44
+ logUserAction({ sessionCookie, userAgent });
45
+ });
46
+
47
+ return new Response(JSON.stringify({ status: "success" }));
48
+ }
49
+ ```
50
+
51
+ Common use cases: analytics tracking, audit logging, notifications, cache invalidation.
52
+
53
+ `after()` runs even if the response fails or redirects. Works in Server Actions, Route Handlers, and Server Components.
54
+
55
+ Reference: [next/server after()](https://nextjs.org/docs/app/api-reference/functions/after)
56
+
57
+ ---
58
+
59
+ ## Authenticate Server Actions
60
+
61
+ Server Actions (`"use server"`) are exposed as public endpoints. Always verify authentication and authorization **inside** each Server Action -- do not rely solely on middleware or layout guards.
62
+
63
+ **Incorrect (no authentication check):**
64
+
65
+ ```typescript
66
+ "use server";
67
+
68
+ export async function deleteUser(userId: string) {
69
+ await db.user.delete({ where: { id: userId } });
70
+ return { success: true };
71
+ }
72
+ ```
73
+
74
+ **Correct (authentication + authorization + validation):**
75
+
76
+ ```typescript
77
+ "use server";
78
+
79
+ import { verifySession } from "@/lib/auth";
80
+ import { z } from "zod";
81
+
82
+ const updateProfileSchema = z.object({
83
+ userId: z.string().uuid(),
84
+ name: z.string().min(1).max(100),
85
+ email: z.string().email(),
86
+ });
87
+
88
+ export async function updateProfile(data: unknown) {
89
+ const validated = updateProfileSchema.parse(data);
90
+ const session = await verifySession();
91
+ if (!session) throw new Error("Unauthorized");
92
+ if (session.user.id !== validated.userId) throw new Error("Can only update own profile");
93
+
94
+ await db.user.update({
95
+ where: { id: validated.userId },
96
+ data: { name: validated.name, email: validated.email },
97
+ });
98
+
99
+ return { success: true };
100
+ }
101
+ ```
102
+
103
+ Reference: [Next.js Authentication Guide](https://nextjs.org/docs/app/guides/authentication)
104
+
105
+ ---
106
+
107
+ ## Cross-Request LRU Caching
108
+
109
+ `React.cache()` only works within one request. For data shared across sequential requests, use an LRU cache.
110
+
111
+ ```typescript
112
+ import { LRUCache } from "lru-cache";
113
+
114
+ const cache = new LRUCache<string, any>({
115
+ max: 1000,
116
+ ttl: 5 * 60 * 1000, // 5 minutes
117
+ });
118
+
119
+ export async function getUser(id: string) {
120
+ const cached = cache.get(id);
121
+ if (cached) return cached;
122
+
123
+ const user = await db.user.findUnique({ where: { id } });
124
+ cache.set(id, user);
125
+ return user;
126
+ }
127
+ ```
128
+
129
+ With Vercel's [Fluid Compute](https://vercel.com/docs/fluid-compute), LRU caching is especially effective because multiple concurrent requests share the same function instance. In traditional serverless, consider Redis for cross-process caching.
130
+
131
+ Reference: [node-lru-cache](https://github.com/isaacs/node-lru-cache)
132
+
133
+ ---
134
+
135
+ ## Per-Request Deduplication with React.cache()
136
+
137
+ Use `React.cache()` for server-side request deduplication. Authentication and database queries benefit most.
138
+
139
+ ```typescript
140
+ import { cache } from "react";
141
+
142
+ export const getCurrentUser = cache(async () => {
143
+ const session = await auth();
144
+ if (!session?.user?.id) return null;
145
+ return await db.user.findUnique({ where: { id: session.user.id } });
146
+ });
147
+ ```
148
+
149
+ **Avoid inline objects as arguments** -- `React.cache()` uses `Object.is` equality. Inline objects always create new references, causing cache misses.
150
+
151
+ ```typescript
152
+ // Incorrect (always cache miss)
153
+ const getUser = cache(async (params: { uid: number }) => {
154
+ /* ... */
155
+ });
156
+ getUser({ uid: 1 });
157
+ getUser({ uid: 1 }); // Miss -- new object reference
158
+
159
+ // Correct (cache hit)
160
+ const getUser = cache(async (uid: number) => {
161
+ /* ... */
162
+ });
163
+ getUser(1);
164
+ getUser(1); // Hit -- same primitive value
165
+ ```
166
+
167
+ **Next.js note:** `fetch` is automatically deduplicated within a single request. `React.cache()` is still essential for database queries, auth checks, heavy computations, and any non-fetch async work.
168
+
169
+ Reference: [React.cache documentation](https://react.dev/reference/react/cache)
170
+
171
+ ---
172
+
173
+ ## Avoid Duplicate Serialization in RSC Props
174
+
175
+ RSC-to-client serialization deduplicates by object reference, not value. Same reference = serialized once; new reference = serialized again. Do transformations in the client, not server.
176
+
177
+ **Incorrect (duplicates array):**
178
+
179
+ ```tsx
180
+ // RSC: sends 6 strings (2 arrays x 3 items)
181
+ <ClientList usernames={usernames} usernamesOrdered={usernames.toSorted()} />
182
+ ```
183
+
184
+ **Correct (sends 3 strings):**
185
+
186
+ ```tsx
187
+ // RSC: send once
188
+ <ClientList usernames={usernames} />;
189
+
190
+ // Client: transform there
191
+ ("use client");
192
+ const sorted = useMemo(() => [...usernames].sort(), [usernames]);
193
+ ```
194
+
195
+ Operations that break deduplication (create new references): `.toSorted()`, `.filter()`, `.map()`, `.slice()`, `[...arr]`, `{...obj}`, `structuredClone()`.
196
+
197
+ **Exception:** Pass derived data when transformation is expensive or client doesn't need the original.
198
+
199
+ ---
200
+
201
+ ## Parallel Data Fetching with Component Composition
202
+
203
+ React Server Components execute sequentially within a tree. Restructure with composition to parallelize data fetching.
204
+
205
+ **Incorrect (Sidebar waits for Page's fetch):**
206
+
207
+ ```tsx
208
+ export default async function Page() {
209
+ const header = await fetchHeader();
210
+ return (
211
+ <div>
212
+ <div>{header}</div>
213
+ <Sidebar />
214
+ </div>
215
+ );
216
+ }
217
+ ```
218
+
219
+ **Correct (both fetch simultaneously):**
220
+
221
+ ```tsx
222
+ async function Header() {
223
+ const data = await fetchHeader();
224
+ return <div>{data}</div>;
225
+ }
226
+
227
+ async function Sidebar() {
228
+ const items = await fetchSidebarItems();
229
+ return <nav>{items.map(renderItem)}</nav>;
230
+ }
231
+
232
+ export default function Page() {
233
+ return (
234
+ <div>
235
+ <Header />
236
+ <Sidebar />
237
+ </div>
238
+ );
239
+ }
240
+ ```
241
+
242
+ ---
243
+
244
+ ## Minimize Serialization at RSC Boundaries
245
+
246
+ The RSC/Client boundary serializes all object properties into the HTML response. Only pass fields that the client actually uses.
247
+
248
+ **Incorrect (serializes all 50 fields):**
249
+
250
+ ```tsx
251
+ async function Page() {
252
+ const user = await fetchUser(); // 50 fields
253
+ return <Profile user={user} />;
254
+ }
255
+
256
+ ("use client");
257
+ function Profile({ user }: { user: User }) {
258
+ return <div>{user.name}</div>; // uses 1 field
259
+ }
260
+ ```
261
+
262
+ **Correct (serializes only 1 field):**
263
+
264
+ ```tsx
265
+ async function Page() {
266
+ const user = await fetchUser();
267
+ return <Profile name={user.name} />;
268
+ }
269
+
270
+ ("use client");
271
+ function Profile({ name }: { name: string }) {
272
+ return <div>{name}</div>;
273
+ }
274
+ ```