@0xsown/vibe-code-fe 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 (189) hide show
  1. package/bin/index.js +181 -0
  2. package/package.json +32 -0
  3. package/skills/claude-md-improver/SKILL.md +179 -0
  4. package/skills/claude-md-improver/references/quality-criteria.md +109 -0
  5. package/skills/claude-md-improver/references/templates.md +253 -0
  6. package/skills/claude-md-improver/references/update-guidelines.md +150 -0
  7. package/skills/find-skills/SKILL.md +133 -0
  8. package/skills/frontend-design/LICENSE.txt +177 -0
  9. package/skills/frontend-design/SKILL.md +42 -0
  10. package/skills/next-best-practices/SKILL.md +153 -0
  11. package/skills/next-best-practices/async-patterns.md +87 -0
  12. package/skills/next-best-practices/bundling.md +180 -0
  13. package/skills/next-best-practices/data-patterns.md +297 -0
  14. package/skills/next-best-practices/debug-tricks.md +105 -0
  15. package/skills/next-best-practices/directives.md +73 -0
  16. package/skills/next-best-practices/error-handling.md +227 -0
  17. package/skills/next-best-practices/file-conventions.md +140 -0
  18. package/skills/next-best-practices/font.md +245 -0
  19. package/skills/next-best-practices/functions.md +108 -0
  20. package/skills/next-best-practices/hydration-error.md +91 -0
  21. package/skills/next-best-practices/image.md +173 -0
  22. package/skills/next-best-practices/metadata.md +301 -0
  23. package/skills/next-best-practices/parallel-routes.md +287 -0
  24. package/skills/next-best-practices/route-handlers.md +146 -0
  25. package/skills/next-best-practices/rsc-boundaries.md +159 -0
  26. package/skills/next-best-practices/runtime-selection.md +39 -0
  27. package/skills/next-best-practices/scripts.md +141 -0
  28. package/skills/next-best-practices/self-hosting.md +371 -0
  29. package/skills/next-best-practices/suspense-boundaries.md +67 -0
  30. package/skills/next-cache-components/SKILL.md +411 -0
  31. package/skills/shadcn-ui/README.md +248 -0
  32. package/skills/shadcn-ui/SKILL.md +326 -0
  33. package/skills/shadcn-ui/examples/auth-layout.tsx +177 -0
  34. package/skills/shadcn-ui/examples/data-table.tsx +313 -0
  35. package/skills/shadcn-ui/examples/form-pattern.tsx +177 -0
  36. package/skills/shadcn-ui/resources/component-catalog.md +481 -0
  37. package/skills/shadcn-ui/resources/customization-guide.md +516 -0
  38. package/skills/shadcn-ui/resources/migration-guide.md +463 -0
  39. package/skills/shadcn-ui/resources/setup-guide.md +412 -0
  40. package/skills/shadcn-ui/scripts/verify-setup.sh +134 -0
  41. package/skills/supabase-postgres-best-practices/AGENTS.md +68 -0
  42. package/skills/supabase-postgres-best-practices/CLAUDE.md +68 -0
  43. package/skills/supabase-postgres-best-practices/README.md +116 -0
  44. package/skills/supabase-postgres-best-practices/SKILL.md +64 -0
  45. package/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
  46. package/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
  47. package/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
  48. package/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
  49. package/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
  50. package/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
  51. package/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
  52. package/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
  53. package/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
  54. package/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
  55. package/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
  56. package/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
  57. package/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
  58. package/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
  59. package/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
  60. package/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
  61. package/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
  62. package/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
  63. package/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
  64. package/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
  65. package/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
  66. package/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
  67. package/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
  68. package/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
  69. package/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
  70. package/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
  71. package/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
  72. package/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
  73. package/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
  74. package/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
  75. package/skills/supabase-postgres-best-practices/references/security-rls-performance.md +57 -0
  76. package/skills/tailwind-design-system/SKILL.md +874 -0
  77. package/skills/vercel-composition-patterns/AGENTS.md +946 -0
  78. package/skills/vercel-composition-patterns/README.md +60 -0
  79. package/skills/vercel-composition-patterns/SKILL.md +89 -0
  80. package/skills/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
  81. package/skills/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
  82. package/skills/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
  83. package/skills/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
  84. package/skills/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
  85. package/skills/vercel-composition-patterns/rules/state-context-interface.md +191 -0
  86. package/skills/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
  87. package/skills/vercel-composition-patterns/rules/state-lift-state.md +125 -0
  88. package/skills/vercel-react-best-practices/AGENTS.md +2934 -0
  89. package/skills/vercel-react-best-practices/README.md +123 -0
  90. package/skills/vercel-react-best-practices/SKILL.md +136 -0
  91. package/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  92. package/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
  93. package/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
  94. package/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
  95. package/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
  96. package/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
  97. package/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
  98. package/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
  99. package/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
  100. package/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
  101. package/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  102. package/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  103. package/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
  104. package/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
  105. package/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
  106. package/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
  107. package/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
  108. package/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
  109. package/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
  110. package/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
  111. package/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
  112. package/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
  113. package/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
  114. package/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
  115. package/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
  116. package/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
  117. package/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
  118. package/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
  119. package/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  120. package/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
  121. package/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  122. package/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
  123. package/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
  124. package/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  125. package/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  126. package/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
  127. package/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
  128. package/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  129. package/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
  130. package/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
  131. package/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  132. package/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
  133. package/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  134. package/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  135. package/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
  136. package/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
  137. package/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  138. package/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  139. package/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
  140. package/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  141. package/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
  142. package/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
  143. package/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
  144. package/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
  145. package/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
  146. package/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
  147. package/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
  148. package/skills/vercel-react-native-skills/AGENTS.md +2897 -0
  149. package/skills/vercel-react-native-skills/README.md +165 -0
  150. package/skills/vercel-react-native-skills/SKILL.md +121 -0
  151. package/skills/vercel-react-native-skills/rules/animation-derived-value.md +53 -0
  152. package/skills/vercel-react-native-skills/rules/animation-gesture-detector-press.md +95 -0
  153. package/skills/vercel-react-native-skills/rules/animation-gpu-properties.md +65 -0
  154. package/skills/vercel-react-native-skills/rules/design-system-compound-components.md +66 -0
  155. package/skills/vercel-react-native-skills/rules/fonts-config-plugin.md +71 -0
  156. package/skills/vercel-react-native-skills/rules/imports-design-system-folder.md +68 -0
  157. package/skills/vercel-react-native-skills/rules/js-hoist-intl.md +61 -0
  158. package/skills/vercel-react-native-skills/rules/list-performance-callbacks.md +44 -0
  159. package/skills/vercel-react-native-skills/rules/list-performance-function-references.md +132 -0
  160. package/skills/vercel-react-native-skills/rules/list-performance-images.md +53 -0
  161. package/skills/vercel-react-native-skills/rules/list-performance-inline-objects.md +97 -0
  162. package/skills/vercel-react-native-skills/rules/list-performance-item-expensive.md +94 -0
  163. package/skills/vercel-react-native-skills/rules/list-performance-item-memo.md +82 -0
  164. package/skills/vercel-react-native-skills/rules/list-performance-item-types.md +104 -0
  165. package/skills/vercel-react-native-skills/rules/list-performance-virtualize.md +67 -0
  166. package/skills/vercel-react-native-skills/rules/monorepo-native-deps-in-app.md +46 -0
  167. package/skills/vercel-react-native-skills/rules/monorepo-single-dependency-versions.md +63 -0
  168. package/skills/vercel-react-native-skills/rules/navigation-native-navigators.md +188 -0
  169. package/skills/vercel-react-native-skills/rules/react-compiler-destructure-functions.md +50 -0
  170. package/skills/vercel-react-native-skills/rules/react-compiler-reanimated-shared-values.md +48 -0
  171. package/skills/vercel-react-native-skills/rules/react-state-dispatcher.md +91 -0
  172. package/skills/vercel-react-native-skills/rules/react-state-fallback.md +56 -0
  173. package/skills/vercel-react-native-skills/rules/react-state-minimize.md +65 -0
  174. package/skills/vercel-react-native-skills/rules/rendering-no-falsy-and.md +74 -0
  175. package/skills/vercel-react-native-skills/rules/rendering-text-in-text-component.md +36 -0
  176. package/skills/vercel-react-native-skills/rules/scroll-position-no-state.md +82 -0
  177. package/skills/vercel-react-native-skills/rules/state-ground-truth.md +80 -0
  178. package/skills/vercel-react-native-skills/rules/ui-expo-image.md +66 -0
  179. package/skills/vercel-react-native-skills/rules/ui-image-gallery.md +104 -0
  180. package/skills/vercel-react-native-skills/rules/ui-measure-views.md +78 -0
  181. package/skills/vercel-react-native-skills/rules/ui-menus.md +174 -0
  182. package/skills/vercel-react-native-skills/rules/ui-native-modals.md +77 -0
  183. package/skills/vercel-react-native-skills/rules/ui-pressable.md +61 -0
  184. package/skills/vercel-react-native-skills/rules/ui-safe-area-scroll.md +65 -0
  185. package/skills/vercel-react-native-skills/rules/ui-scrollview-content-inset.md +45 -0
  186. package/skills/vercel-react-native-skills/rules/ui-styling.md +87 -0
  187. package/skills/web-design-guidelines/SKILL.md +39 -0
  188. package/templates/AGENTS.md +31 -0
  189. package/templates/CLAUDE.md +31 -0
@@ -0,0 +1,141 @@
1
+ # Scripts
2
+
3
+ Loading third-party scripts in Next.js.
4
+
5
+ ## Use next/script
6
+
7
+ Always use `next/script` instead of native `<script>` tags for better performance.
8
+
9
+ ```tsx
10
+ // Bad: Native script tag
11
+ <script src="https://example.com/script.js"></script>
12
+
13
+ // Good: Next.js Script component
14
+ import Script from 'next/script'
15
+
16
+ <Script src="https://example.com/script.js" />
17
+ ```
18
+
19
+ ## Inline Scripts Need ID
20
+
21
+ Inline scripts require an `id` attribute for Next.js to track them.
22
+
23
+ ```tsx
24
+ // Bad: Missing id
25
+ <Script dangerouslySetInnerHTML={{ __html: 'console.log("hi")' }} />
26
+
27
+ // Good: Has id
28
+ <Script id="my-script" dangerouslySetInnerHTML={{ __html: 'console.log("hi")' }} />
29
+
30
+ // Good: Inline with id
31
+ <Script id="show-banner">
32
+ {`document.getElementById('banner').classList.remove('hidden')`}
33
+ </Script>
34
+ ```
35
+
36
+ ## Don't Put Script in Head
37
+
38
+ `next/script` should not be placed inside `next/head`. It handles its own positioning.
39
+
40
+ ```tsx
41
+ // Bad: Script inside Head
42
+ import Head from 'next/head'
43
+ import Script from 'next/script'
44
+
45
+ <Head>
46
+ <Script src="/analytics.js" />
47
+ </Head>
48
+
49
+ // Good: Script outside Head
50
+ <Head>
51
+ <title>Page</title>
52
+ </Head>
53
+ <Script src="/analytics.js" />
54
+ ```
55
+
56
+ ## Loading Strategies
57
+
58
+ ```tsx
59
+ // afterInteractive (default) - Load after page is interactive
60
+ <Script src="/analytics.js" strategy="afterInteractive" />
61
+
62
+ // lazyOnload - Load during idle time
63
+ <Script src="/widget.js" strategy="lazyOnload" />
64
+
65
+ // beforeInteractive - Load before page is interactive (use sparingly)
66
+ // Only works in app/layout.tsx or pages/_document.js
67
+ <Script src="/critical.js" strategy="beforeInteractive" />
68
+
69
+ // worker - Load in web worker (experimental)
70
+ <Script src="/heavy.js" strategy="worker" />
71
+ ```
72
+
73
+ ## Google Analytics
74
+
75
+ Use `@next/third-parties` instead of inline GA scripts.
76
+
77
+ ```tsx
78
+ // Bad: Inline GA script
79
+ <Script src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX" />
80
+ <Script id="ga-init">
81
+ {`window.dataLayer = window.dataLayer || [];
82
+ function gtag(){dataLayer.push(arguments);}
83
+ gtag('js', new Date());
84
+ gtag('config', 'G-XXXXX');`}
85
+ </Script>
86
+
87
+ // Good: Next.js component
88
+ import { GoogleAnalytics } from '@next/third-parties/google'
89
+
90
+ export default function Layout({ children }) {
91
+ return (
92
+ <html>
93
+ <body>{children}</body>
94
+ <GoogleAnalytics gaId="G-XXXXX" />
95
+ </html>
96
+ )
97
+ }
98
+ ```
99
+
100
+ ## Google Tag Manager
101
+
102
+ ```tsx
103
+ import { GoogleTagManager } from '@next/third-parties/google'
104
+
105
+ export default function Layout({ children }) {
106
+ return (
107
+ <html>
108
+ <GoogleTagManager gtmId="GTM-XXXXX" />
109
+ <body>{children}</body>
110
+ </html>
111
+ )
112
+ }
113
+ ```
114
+
115
+ ## Other Third-Party Scripts
116
+
117
+ ```tsx
118
+ // YouTube embed
119
+ import { YouTubeEmbed } from '@next/third-parties/google'
120
+
121
+ <YouTubeEmbed videoid="dQw4w9WgXcQ" />
122
+
123
+ // Google Maps
124
+ import { GoogleMapsEmbed } from '@next/third-parties/google'
125
+
126
+ <GoogleMapsEmbed
127
+ apiKey="YOUR_API_KEY"
128
+ mode="place"
129
+ q="Brooklyn+Bridge,New+York,NY"
130
+ />
131
+ ```
132
+
133
+ ## Quick Reference
134
+
135
+ | Pattern | Issue | Fix |
136
+ |---------|-------|-----|
137
+ | `<script src="...">` | No optimization | Use `next/script` |
138
+ | `<Script>` without id | Can't track inline scripts | Add `id` attribute |
139
+ | `<Script>` inside `<Head>` | Wrong placement | Move outside Head |
140
+ | Inline GA/GTM scripts | No optimization | Use `@next/third-parties` |
141
+ | `strategy="beforeInteractive"` outside layout | Won't work | Only use in root layout |
@@ -0,0 +1,371 @@
1
+ # Self-Hosting Next.js
2
+
3
+ Deploy Next.js outside of Vercel with confidence.
4
+
5
+ ## Quick Start: Standalone Output
6
+
7
+ For Docker or any containerized deployment, use standalone output:
8
+
9
+ ```js
10
+ // next.config.js
11
+ module.exports = {
12
+ output: 'standalone',
13
+ };
14
+ ```
15
+
16
+ This creates a minimal `standalone` folder with only production dependencies:
17
+
18
+ ```
19
+ .next/
20
+ ├── standalone/
21
+ │ ├── server.js # Entry point
22
+ │ ├── node_modules/ # Only production deps
23
+ │ └── .next/ # Build output
24
+ └── static/ # Must be copied separately
25
+ ```
26
+
27
+ ## Docker Deployment
28
+
29
+ ### Dockerfile
30
+
31
+ ```dockerfile
32
+ FROM node:20-alpine AS base
33
+
34
+ # Install dependencies
35
+ FROM base AS deps
36
+ WORKDIR /app
37
+ COPY package.json package-lock.json* ./
38
+ RUN npm ci
39
+
40
+ # Build
41
+ FROM base AS builder
42
+ WORKDIR /app
43
+ COPY --from=deps /app/node_modules ./node_modules
44
+ COPY . .
45
+ RUN npm run build
46
+
47
+ # Production
48
+ FROM base AS runner
49
+ WORKDIR /app
50
+
51
+ ENV NODE_ENV=production
52
+
53
+ # Create non-root user
54
+ RUN addgroup --system --gid 1001 nodejs
55
+ RUN adduser --system --uid 1001 nextjs
56
+
57
+ # Copy standalone output
58
+ COPY --from=builder /app/.next/standalone ./
59
+ COPY --from=builder /app/.next/static ./.next/static
60
+ COPY --from=builder /app/public ./public
61
+
62
+ USER nextjs
63
+
64
+ EXPOSE 3000
65
+ ENV PORT=3000
66
+ ENV HOSTNAME="0.0.0.0"
67
+
68
+ CMD ["node", "server.js"]
69
+ ```
70
+
71
+ ### Docker Compose
72
+
73
+ ```yaml
74
+ version: '3.8'
75
+
76
+ services:
77
+ web:
78
+ build: .
79
+ ports:
80
+ - "3000:3000"
81
+ environment:
82
+ - NODE_ENV=production
83
+ restart: unless-stopped
84
+ healthcheck:
85
+ test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/api/health"]
86
+ interval: 30s
87
+ timeout: 10s
88
+ retries: 3
89
+ ```
90
+
91
+ ## PM2 Deployment
92
+
93
+ For traditional server deployments:
94
+
95
+ ```js
96
+ // ecosystem.config.js
97
+ module.exports = {
98
+ apps: [{
99
+ name: 'nextjs',
100
+ script: '.next/standalone/server.js',
101
+ instances: 'max',
102
+ exec_mode: 'cluster',
103
+ env: {
104
+ NODE_ENV: 'production',
105
+ PORT: 3000,
106
+ },
107
+ }],
108
+ };
109
+ ```
110
+
111
+ ```bash
112
+ npm run build
113
+ pm2 start ecosystem.config.js
114
+ ```
115
+
116
+ ## ISR and Cache Handlers
117
+
118
+ ### The Problem
119
+
120
+ ISR (Incremental Static Regeneration) uses filesystem caching by default. This **breaks with multiple instances**:
121
+
122
+ - Instance A regenerates page → saves to its local disk
123
+ - Instance B serves stale page → doesn't see Instance A's cache
124
+ - Load balancer sends users to random instances → inconsistent content
125
+
126
+ ### Solution: Custom Cache Handler
127
+
128
+ Next.js 14+ supports custom cache handlers for shared storage:
129
+
130
+ ```js
131
+ // next.config.js
132
+ module.exports = {
133
+ cacheHandler: require.resolve('./cache-handler.js'),
134
+ cacheMaxMemorySize: 0, // Disable in-memory cache
135
+ };
136
+ ```
137
+
138
+ #### Redis Cache Handler Example
139
+
140
+ ```js
141
+ // cache-handler.js
142
+ const Redis = require('ioredis');
143
+
144
+ const redis = new Redis(process.env.REDIS_URL);
145
+ const CACHE_PREFIX = 'nextjs:';
146
+
147
+ module.exports = class CacheHandler {
148
+ constructor(options) {
149
+ this.options = options;
150
+ }
151
+
152
+ async get(key) {
153
+ const data = await redis.get(CACHE_PREFIX + key);
154
+ if (!data) return null;
155
+
156
+ const parsed = JSON.parse(data);
157
+ return {
158
+ value: parsed.value,
159
+ lastModified: parsed.lastModified,
160
+ };
161
+ }
162
+
163
+ async set(key, data, ctx) {
164
+ const cacheData = {
165
+ value: data,
166
+ lastModified: Date.now(),
167
+ };
168
+
169
+ // Set TTL based on revalidate option
170
+ if (ctx?.revalidate) {
171
+ await redis.setex(
172
+ CACHE_PREFIX + key,
173
+ ctx.revalidate,
174
+ JSON.stringify(cacheData)
175
+ );
176
+ } else {
177
+ await redis.set(CACHE_PREFIX + key, JSON.stringify(cacheData));
178
+ }
179
+ }
180
+
181
+ async revalidateTag(tags) {
182
+ // Implement tag-based invalidation
183
+ // This requires tracking which keys have which tags
184
+ }
185
+ };
186
+ ```
187
+
188
+ #### S3 Cache Handler Example
189
+
190
+ ```js
191
+ // cache-handler.js
192
+ const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
193
+
194
+ const s3 = new S3Client({ region: process.env.AWS_REGION });
195
+ const BUCKET = process.env.CACHE_BUCKET;
196
+
197
+ module.exports = class CacheHandler {
198
+ async get(key) {
199
+ try {
200
+ const response = await s3.send(new GetObjectCommand({
201
+ Bucket: BUCKET,
202
+ Key: `cache/${key}`,
203
+ }));
204
+ const body = await response.Body.transformToString();
205
+ return JSON.parse(body);
206
+ } catch (err) {
207
+ if (err.name === 'NoSuchKey') return null;
208
+ throw err;
209
+ }
210
+ }
211
+
212
+ async set(key, data, ctx) {
213
+ await s3.send(new PutObjectCommand({
214
+ Bucket: BUCKET,
215
+ Key: `cache/${key}`,
216
+ Body: JSON.stringify({
217
+ value: data,
218
+ lastModified: Date.now(),
219
+ }),
220
+ ContentType: 'application/json',
221
+ }));
222
+ }
223
+ };
224
+ ```
225
+
226
+ ## What Works vs What Needs Setup
227
+
228
+ | Feature | Single Instance | Multi-Instance | Notes |
229
+ |---------|----------------|----------------|-------|
230
+ | SSR | Yes | Yes | No special setup |
231
+ | SSG | Yes | Yes | Built at deploy time |
232
+ | ISR | Yes | Needs cache handler | Filesystem cache breaks |
233
+ | Image Optimization | Yes | Yes | CPU-intensive, consider CDN |
234
+ | Middleware | Yes | Yes | Runs on Node.js |
235
+ | Edge Runtime | Limited | Limited | Some features Node-only |
236
+ | `revalidatePath/Tag` | Yes | Needs cache handler | Must share cache |
237
+ | `next/font` | Yes | Yes | Fonts bundled at build |
238
+ | Draft Mode | Yes | Yes | Cookie-based |
239
+
240
+ ## Image Optimization
241
+
242
+ Next.js Image Optimization works out of the box but is CPU-intensive.
243
+
244
+ ### Option 1: Built-in (Simple)
245
+
246
+ Works automatically, but consider:
247
+ - Set `deviceSizes` and `imageSizes` in config to limit variants
248
+ - Use `minimumCacheTTL` to reduce regeneration
249
+
250
+ ```js
251
+ // next.config.js
252
+ module.exports = {
253
+ images: {
254
+ minimumCacheTTL: 60 * 60 * 24, // 24 hours
255
+ deviceSizes: [640, 750, 1080, 1920], // Limit sizes
256
+ },
257
+ };
258
+ ```
259
+
260
+ ### Option 2: External Loader (Recommended for Scale)
261
+
262
+ Offload to Cloudinary, Imgix, or similar:
263
+
264
+ ```js
265
+ // next.config.js
266
+ module.exports = {
267
+ images: {
268
+ loader: 'custom',
269
+ loaderFile: './lib/image-loader.js',
270
+ },
271
+ };
272
+ ```
273
+
274
+ ```js
275
+ // lib/image-loader.js
276
+ export default function cloudinaryLoader({ src, width, quality }) {
277
+ const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`];
278
+ return `https://res.cloudinary.com/demo/image/upload/${params.join(',')}${src}`;
279
+ }
280
+ ```
281
+
282
+ ## Environment Variables
283
+
284
+ ### Build-time vs Runtime
285
+
286
+ ```js
287
+ // Available at build time only (baked into bundle)
288
+ NEXT_PUBLIC_API_URL=https://api.example.com
289
+
290
+ // Available at runtime (server-side only)
291
+ DATABASE_URL=postgresql://...
292
+ API_SECRET=...
293
+ ```
294
+
295
+ ### Runtime Configuration
296
+
297
+ For truly dynamic config, don't use `NEXT_PUBLIC_*`. Instead:
298
+
299
+ ```tsx
300
+ // app/api/config/route.ts
301
+ export async function GET() {
302
+ return Response.json({
303
+ apiUrl: process.env.API_URL,
304
+ features: process.env.FEATURES?.split(','),
305
+ });
306
+ }
307
+ ```
308
+
309
+ ## OpenNext: Serverless Without Vercel
310
+
311
+ [OpenNext](https://open-next.js.org/) adapts Next.js for AWS Lambda, Cloudflare Workers, etc.
312
+
313
+ ```bash
314
+ npx create-sst@latest
315
+ # or
316
+ npx @opennextjs/aws build
317
+ ```
318
+
319
+ Supports:
320
+ - AWS Lambda + CloudFront
321
+ - Cloudflare Workers
322
+ - Netlify Functions
323
+ - Deno Deploy
324
+
325
+ ## Health Check Endpoint
326
+
327
+ Always include a health check for load balancers:
328
+
329
+ ```tsx
330
+ // app/api/health/route.ts
331
+ export async function GET() {
332
+ try {
333
+ // Optional: check database connection
334
+ // await db.$queryRaw`SELECT 1`;
335
+
336
+ return Response.json({ status: 'healthy' }, { status: 200 });
337
+ } catch (error) {
338
+ return Response.json({ status: 'unhealthy' }, { status: 503 });
339
+ }
340
+ }
341
+ ```
342
+
343
+ ## Pre-Deployment Checklist
344
+
345
+ 1. **Build locally first**: `npm run build` - catch errors before deploy
346
+ 2. **Test standalone output**: `node .next/standalone/server.js`
347
+ 3. **Set `output: 'standalone'`** for Docker
348
+ 4. **Configure cache handler** for multi-instance ISR
349
+ 5. **Set `HOSTNAME="0.0.0.0"`** for containers
350
+ 6. **Copy `public/` and `.next/static/`** - not included in standalone
351
+ 7. **Add health check endpoint**
352
+ 8. **Test ISR revalidation** after deployment
353
+ 9. **Monitor memory usage** - Node.js defaults may need tuning
354
+
355
+ ## Testing Cache Handler
356
+
357
+ **Critical**: Test your cache handler on every Next.js upgrade:
358
+
359
+ ```bash
360
+ # Start multiple instances
361
+ PORT=3001 node .next/standalone/server.js &
362
+ PORT=3002 node .next/standalone/server.js &
363
+
364
+ # Trigger ISR revalidation
365
+ curl http://localhost:3001/api/revalidate?path=/posts
366
+
367
+ # Verify both instances see the update
368
+ curl http://localhost:3001/posts
369
+ curl http://localhost:3002/posts
370
+ # Should return identical content
371
+ ```
@@ -0,0 +1,67 @@
1
+ # Suspense Boundaries
2
+
3
+ Client hooks that cause CSR bailout without Suspense boundaries.
4
+
5
+ ## useSearchParams
6
+
7
+ Always requires Suspense boundary in static routes. Without it, the entire page becomes client-side rendered.
8
+
9
+ ```tsx
10
+ // Bad: Entire page becomes CSR
11
+ 'use client'
12
+
13
+ import { useSearchParams } from 'next/navigation'
14
+
15
+ export default function SearchBar() {
16
+ const searchParams = useSearchParams()
17
+ return <div>Query: {searchParams.get('q')}</div>
18
+ }
19
+ ```
20
+
21
+ ```tsx
22
+ // Good: Wrap in Suspense
23
+ import { Suspense } from 'react'
24
+ import SearchBar from './search-bar'
25
+
26
+ export default function Page() {
27
+ return (
28
+ <Suspense fallback={<div>Loading...</div>}>
29
+ <SearchBar />
30
+ </Suspense>
31
+ )
32
+ }
33
+ ```
34
+
35
+ ## usePathname
36
+
37
+ Requires Suspense boundary when route has dynamic parameters.
38
+
39
+ ```tsx
40
+ // In dynamic route [slug]
41
+ // Bad: No Suspense
42
+ 'use client'
43
+ import { usePathname } from 'next/navigation'
44
+
45
+ export function Breadcrumb() {
46
+ const pathname = usePathname()
47
+ return <nav>{pathname}</nav>
48
+ }
49
+ ```
50
+
51
+ ```tsx
52
+ // Good: Wrap in Suspense
53
+ <Suspense fallback={<BreadcrumbSkeleton />}>
54
+ <Breadcrumb />
55
+ </Suspense>
56
+ ```
57
+
58
+ If you use `generateStaticParams`, Suspense is optional.
59
+
60
+ ## Quick Reference
61
+
62
+ | Hook | Suspense Required |
63
+ |------|-------------------|
64
+ | `useSearchParams()` | Yes |
65
+ | `usePathname()` | Yes (dynamic routes) |
66
+ | `useParams()` | No |
67
+ | `useRouter()` | No |