opinionated-nextjs-patterns
Opinionated, backend-agnostic Next.js 16 (App Router) architecture — authorization at the data layer, server-side loading with cache()+Promise.all, mutations through next-safe-action + typed route handlers, client/server boundaries ('use client' at leaves + TanStack Query), forms with RHF + Zod, UI via shadcn/ui + Tailwind + Base UI + next-intl, request handling in proxy.ts (Next.js 16's renamed middleware), and a Turbo monorepo of @app/* packages confining the backend behind one data-access package. Examples use Supabase but every rule states the transferable principle. Use when writing, reviewing, or refactoring Next.js 16 code. Trigger on server actions, route handlers, RSC vs 'use client' placement, TanStack Query, RHF/Zod, proxy.ts, or monorepo package layout — even when the user doesn't say 'patterns' or 'best practices'.
How do I install this agent skill?
npx skills add https://github.com/pproenca/dot-skills --skill opinionated-nextjs-patternsIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The skill is a comprehensive architectural and security reference guide for building Next.js 16 applications. It provides 50 detailed rules that emphasize security best practices, such as data-layer authorization (RLS), centralized authentication, and secure request boundaries. No malicious patterns, obfuscation, or data exfiltration attempts were detected.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
Opinionated Next.js 16 Patterns
Implementation-pattern reference for Next.js 16 (App Router) codebases that want a single, opinionated architecture. Contains 50 rules across 8 categories, prioritised by execution-lifecycle cascade impact — authorization and (optional) tenant modeling first, then the request boundary, server fetching, mutations, client boundaries, architecture, and UI conventions.
The rules are backend-agnostic in principle but use Supabase as the concrete example. Each rule teaches the transferable idea (e.g. "authorize at the data layer", "read through a typed repository"); where the backend genuinely matters, a *Transferable:* note explains the pattern for other stores (Drizzle, Prisma). The structure is a Turbo monorepo with @app/* packages you own — built on canonical libraries (next-safe-action, @supabase/ssr, @tanstack/react-query, react-hook-form + zod, shadcn/ui, next-intl, pino), not a vendored starter kit.
When to Apply
Reach for these rules when:
- Writing new code — pages, layouts, server actions, route handlers,
proxy.ts, feature packages, client components, hooks, the data-access package, SQL/migrations, forms. - Reviewing a PR — authorization slips (privileged client without a guard, missing
'server-only'), waterfalls (sequential awaits, client-fetching server data), drift (hand-edited generated types, deep package imports, hardcoded i18n strings). - Refactoring — moving code between
apps/webandpackages/*, splitting actions and services, lifting'use client'boundaries, replacing raw queries with a typed data-access factory, swapping a backend behind the data-access package. - Designing a feature — choosing the right client (request-scoped vs privileged vs browser), deciding action vs route handler, planning the form/server-action contract, scoping a tenant (if multi-tenant).
- Onboarding — understanding why the codebase looks the way it does, with concrete, transferable examples.
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Authorization & Data-Layer Access | CRITICAL | auth- |
| 2 | Multi-Tenancy (optional, SaaS only) | CRITICAL | tenant- |
| 3 | Request Boundary (Proxy) | HIGH | proxy- |
| 4 | Server-Side Data Loading | HIGH | server- |
| 5 | Mutations: Actions & Route Handlers | HIGH | mutate- |
| 6 | Client/Server Boundaries | MEDIUM-HIGH | client- |
| 7 | Architecture & Services | MEDIUM | arch- |
| 8 | Forms & UI Conventions | MEDIUM | ui- |
Quick Reference
1. Authorization & Data-Layer Access (CRITICAL)
auth-use-standard-server-client— Use the request-scoped, auth-bound client; never default to the privileged one.auth-gate-admin-client— Authorize before constructing the service-role client.auth-trust-rls-no-duplicate-checks— Authorize once at the data layer; don't re-check in app code.auth-use-sql-policy-helpers— Centralize scoping predicates in reusable SQL policy helpers.auth-use-require-user— Centralize the auth gate in onerequireUser()helper.auth-server-only-imports— Mark privileged modules withimport 'server-only'.auth-mfa-in-middleware— Enforce MFA at theproxy.tsboundary, not per-page.
2. Multi-Tenancy (CRITICAL — optional, SaaS only)
tenant-accounts-as-tenant-root— One tenant-root table both personal and team workspaces reference.tenant-account-id-on-product-tables— Tenant key + index + scoping policy on every product table.tenant-slug-in-team-urls— Use a human-readable slug in team URLs, not the UUID.tenant-storage-paths-include-account-id— Namespace object-storage paths by tenant id.tenant-never-edit-generated-types— Treat generated DB types as build output; regenerate, never hand-edit.
3. Request Boundary: Proxy (HIGH)
proxy-single-pipeline— Compose the whole request pipeline in oneproxy.ts.proxy-redirect-auth-at-boundary— Perform auth redirects at the proxy, not in pages.proxy-url-pattern-matching— Match proxy routes withURLPattern, not string comparisons.proxy-set-correlation-id— Set a correlation ID at the request boundary.proxy-secure-headers-flagged— Apply strict CSP headers behind an environment flag.
4. Server-Side Data Loading (HIGH)
server-cache-workspace-loaders— Wrap per-request loaders withcache()from React.server-promise-all-parallel-loads— Load independent data in parallel withPromise.all.server-use-feature-api-factories— Read through a typed data-access factory, not rawfrom('table').server-redirect-on-missing-workspace— Redirect from the loader when workspace state is invalid.server-fetch-in-server-components— Fetch initial data in server components, not on the client.server-use-tables-generic-for-types— Use generated row types, not hand-written interfaces.server-services-receive-client— Services receive the data client as a constructor argument.
5. Mutations: Actions & Route Handlers (HIGH)
mutate-use-safe-action-clients— Route mutations through a typed action client you build on next-safe-action.mutate-zod-schema-separate-file— Put Zod schemas in their own*.schema.tsshared by client and server.mutate-thin-action-service-holds-logic— Keep the action thin; put business logic in a service.mutate-use-getlogger-not-console— Log through a structured logger you own, notconsole.log.mutate-revalidate-path-after-write— CallrevalidatePath()after a successful write.mutate-enhance-route-handler— Wrap route handlers in a typed handler that owns auth and validation.mutate-webhook-verify-signature— Webhook routes skip user-auth and verify the provider signature.
6. Client/Server Boundaries (MEDIUM-HIGH)
client-use-client-at-leaves— Mark'use client'at leaf components, not page roots.client-pass-server-data-as-props— Pass server data to client components as props, don't refetch.client-use-supabase-with-react-query— Pair a memoized browser client with TanStack Query for client reads.client-realtime-cleanup-subscription— Tear down any subscription or event source in theuseEffectreturn.client-use-action-hook— Call server actions withuseActionfromnext-safe-action/hooks.client-stable-query-keys— Use stable, hierarchical query keys.
7. Architecture & Services (MEDIUM)
arch-app-vs-packages-boundary— Reusable capabilities inpackages/, product-specific code inapps/web.arch-data-access-adapter— Confine the backend to one data-access package with a stable surface.arch-feature-package-layout— Feature packages follow acomponents / hooks / schema / serverlayout.arch-import-via-package-exports— Import via the packageexportsmap, never deep internal paths.arch-provider-gateway-pattern— Hide vendor SDKs behind a gateway interface.arch-policy-engine-for-business-rules— Model business rules in a policy layer you own, not inline conditionals.arch-config-driven-navigation— Define routes and navigation inconfig/, not hardcoded in components.
8. Forms & UI Conventions (MEDIUM)
ui-rhf-zod-no-generics— LetzodResolverinfer form types; don't adduseFormgenerics.ui-form-message-per-field— IncludeFormMessagefor every field.ui-kit-ui-package-imports— Import UI from your@app/uidesign-system surface, never internal paths.ui-semantic-tailwind-tokens— Use semantic Tailwind tokens, not hardcoded colors.ui-base-ui-render-not-aschild— Use Base UIrenderprop, not RadixasChild.ui-trans-for-display-text— Render display text through<Trans>oruseTranslations.
How to Use
Read individual reference files for detailed explanations and code examples:
- Section definitions — Category structure, impact levels, lifecycle rationale.
- Rule template — Template for adding new rules.
- AGENTS.md — Auto-generated TOC for fast navigation.
Reference Files
| File | Description |
|---|---|
| references/_sections.md | Category definitions and ordering by lifecycle impact |
| assets/templates/_template.md | Template for adding new rules |
| metadata.json | Version, organization, references |
Related Skills
base-ui-migrator— bulk-migrate RadixasChildpatterns to Base UIrenderprops.tailwind-refactor— refactor hardcoded colors to semantic tokens.react-optimise— performance optimisations for React components.nextjs-bundle-optimizer— bundle analysis and reduction for Next.js apps.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/pproenca/dot-skills/opinionated-nextjs-patterns">View opinionated-nextjs-patterns on skillZs</a>