Communitygithub.com

Nuvraxis/nuvraxis-plugins

Reglas de producción para aplicaciones Next.js 16 App Router en Nuvraxis: límites entre componentes servidor/cliente, componentes de caché ("use cache", cacheLife, cacheTag, updateTag), Server Actions, manejadores de ruta, manejo de entorno, instrumentation, output standalone y la ruta /api/health. Úsalo cuando el proyecto tenga "next" en package.json, un directorio app/ o src/app/, next.config.ts, proxy.ts, instrumentation.ts, o archivos llamados page.tsx, layout.tsx, route.ts, loading.tsx, error.tsx.

¿Qué es nuvraxis-plugins?

Esta skill define las reglas de producción para aplicaciones Next.js 16 App Router en Nuvraxis. Se enfoca en detalles específicos de construcción y despliegue que complementan las habilidades generales de Next.js, como la separación entre componentes servidor y cliente, el uso de componentes de caché con "use cache", cacheLife, cacheTag y updateTag, y la validación y autorización obligatoria en Server Actions. También cubre manejadores de ruta, manejo de variables de entorno (con especial atención a NEXT_PUBLIC_*), la ruta de salud /api/health, y la configuración de output standalone para autoalojamiento. Soporta los proyectos que tengan "next" en package.json, un directorio app/ o src/app/, next.config.ts, proxy.ts, instrumentation.ts, o archivos típicos de Next.js. La skill asume Next.js 16.4, React 19.3, Turbopack, y características como typedRoutes: true y cacheComponents: true.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Nuvraxis/nuvraxis-plugins/tree/HEAD/plugins/nuvraxis-frontend/skills/nextjs-production

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Next.js en producción

Úsalo para cualquier código en una aplicación Next.js 16 App Router. Las reglas específicas de seguridad (autenticación en acciones, CSP, cabeceras, taint) están en nextjs-security; las reglas de contenedor en docker-nextjs. La skill integrada de Claude Code next-best-practices cubre las convenciones generales de archivos, metadatos, optimización de imágenes y fuentes en profundidad; esta skill solo agrega lo específico de cómo construimos y publicamos.

Línea base: Next 16.4, React 19.3, Turbopack (predeterminado para dev y build), cacheComponents: true con partialPrefetching: true, output: "standalone", typedRoutes: true. El next.config.ts de la plantilla es la fuente de verdad.

Reglas

  1. Componentes servidor por defecto; "use client" solo para estado, efectos, APIs del navegador o manejadores de eventos. Pon la directiva en la hoja más pequeña que la necesite. No la agregues porque un archivo importa nuvui: las partes con estado de nuvui llevan su propia directiva (consulta la skill nuvui, rules/server-components.md).

    // Mal: toda la página es cliente por un solo manejador
    "use client";
    export default function Page() { … <Select onValueChange={…} /> … }
    
    // Bien: la página permanece en el servidor, el manejador vive en una hoja
    export default async function Page() {
      const people = await getPeople();
      return <PeopleFilter people={people} />; // people-filter.tsx tiene "use client"
    }
    

    Las props que cruzan a un componente cliente deben ser serializables: sin funciones (excepto Server Actions), sin instancias de clase.

  2. Obtén datos en el servidor, en el componente que necesita los datos. Sin useEffect para obtener datos, sin manejador de ruta solo para alimentar tu propia página. Desduplica por solicitud con cache() de React; almacena en caché entre solicitudes con la regla 3.

  3. Almacena en caché con "use cache" + cacheLife + cacheTag; todo lo demás es dinámico. Con Componentes de Caché, nada se almacena en caché a menos que lo indiques, y fetch no tiene caché implícita.

    import { cacheLife, cacheTag } from "next/cache";
    
    export async function getInvoice(id: InvoiceId) {
      "use cache";
      cacheLife("minutes");
      cacheTag(`invoice:${id}`);
      return db.invoice.findUnique({ where: { id } });
    }
    

    No uses la configuración de segmento antigua (export const dynamic, revalidate, fetchCache): da error bajo Componentes de Caché. Los argumentos y valores cerrados pasan a formar parte de la clave de caché, así que pasa ids, no objetos de solicitud completos. Detalles, los perfiles y "use cache: private": references/caching.md.

  4. Invalida con updateTag en Server Actions, revalidateTag(tag, "max") en otros lugares. updateTag(tag) proporciona consistencia de lectura-después-de-escritura y solo funciona dentro de una Server Action. Desde un webhook o manejador de ruta usa revalidateTag(tag, "max") (stale-while-revalidate) o revalidateTag(tag, { expire: 0 }). La versión de un solo argumento revalidateTag(tag) está obsoleta.

  5. Envuelve los datos en tiempo de solicitud en <Suspense>, o la compilación falla. cookies(), headers(), searchParams, connection() y E/S no almacenada en caché fuera de un límite de Suspense detienen el prerenderizado con "datos no almacenados en caché o en tiempo de ejecución durante el prerenderizado". Asígnale un límite con un fallback esqueleto, almacena en caché, o (solo en el layout raíz, ver regla 14) marca la ruta como bloqueante con export const instant = false. Todos params, searchParams, cookies(), headers() son asíncronos: haz await de ellos.

  6. Cada Server Action valida su entrada y verifica la autorización por sí misma. Una Server Action es un endpoint POST público sin importar en qué página esté escrita. Analiza FormData con el esquema de typescript-production (valibot), luego autoriza, luego muta, luego updateTag. Devuelve un resultado tipado para fallos esperados; lanza solo para errores. El conjunto completo de reglas está en nextjs-security.

    "use server";
    export async function renameProject(_: State, form: FormData): Promise<State> {
      const session = await requireSession();                  // 401 si está ausente
      const input = v.safeParse(RenameProject, Object.fromEntries(form));
      if (!input.success) return { ok: false, errors: flatten(input.issues) };
      await assertCanEdit(session, input.output.projectId);    // 403 si no está permitido
      await db.project.update(…);
      updateTag(`project:${input.output.projectId}`);
      return { ok: true };
    }
    
  7. Los manejadores de ruta son para otros clientes (webhooks, móvil, salud), no para tus propias páginas. Ponlos bajo app/api/. Valida el cuerpo como una acción, devuelve Response.json(...), y establece códigos de estado intencionadamente.

  8. Cada aplicación tiene GET /api/health, dinámico y sin dependencias. El HEALTHCHECK de Docker y los probes de Kubernetes lo golpean. Debe responder sin tocar la base de datos, para que una dependencia lenta no reinicie cada pod. await connection() evita que se prerenderice en un archivo estático. Está en la plantilla en src/app/api/health/route.ts; proxy.ts excluye /api/health de su matcher.

  9. error.tsx, loading.tsx y not-found.tsx en la raíz, y por segmento donde la UX difiere. error.tsx es un componente cliente; registra a través de onRequestError de instrumentation.ts, muestra un reintento con reset, nunca el mensaje de error. Llama a notFound() para registros faltantes en lugar de renderizar un estado vacío.

  10. NEXT_PUBLIC_* se hornea en la compilación; todo lo demás se lee en tiempo de ejecución en el servidor. Una imagen se promociona de main a producción sin cambios, por lo que un valor NEXT_PUBLIC_ es el mismo en todos los entornos. Pon solo constantes de tiempo de compilación allí (nombre de la aplicación, un DSN público de Sentry que es el mismo en todas partes). La configuración por entorno (URLs de API, feature flags, secretos) es un process.env.X del lado del servidor, leído en un Componente Servidor o acción, y pasado al cliente como props si es necesario. Valida el entorno una vez en src/env.ts (valibot) e importa desde allí. Nunca uses la clave env en next.config.ts: se incluye en los bundles del cliente.

  11. Marca los módulos solo de servidor con import "server-only". Cualquier cosa que lea secretos, hable con la base de datos o importe un SDK con credenciales. Una importación de cliente de ello entonces falla la compilación en lugar de filtrar.

  12. after() para trabajo que no debería retrasar la respuesta (registros de auditoría, analíticas, calentamiento de caché). Lee cookies()/headers() antes de llamar a after, no dentro de él. Se ejecuta en el mismo proceso, por lo que el pod necesita su período de gracia SIGTERM (el chart establece terminationGracePeriodSeconds).

  13. Instrumenta con src/instrumentation.ts: registerOTel + onRequestError. OpenTelemetry a través de @vercel/otel, exportador configurado por las variables de entorno estándar OTEL_EXPORTER_OTLP_* en tiempo de ejecución. Consulta references/observability.md.

  14. Mantén output: "standalone" y nunca importes desde fuera del workspace. El runner de Docker copia solo .next/standalone, .next/static y public. En el monorepo, server.js aterriza en .next/standalone/apps/<app>/server.js; la raíz del workspace se encuentra desde pnpm-lock.yaml, así que no establezcas outputFileTracingRoot o turbopack.root a menos que la compilación advierta. Detalles de autoalojamiento (múltiples réplicas, claves de Server Action, deploymentId): references/self-hosting.md.

  15. El layout raíz lee el nonce CSP, por lo que la aplicación se renderiza por solicitud. El proxy.ts de la plantilla establece un CSP basado en nonce y src/app/layout.tsx tiene export const instant = false. Eso es un intercambio deliberado: los nonces y los shells estáticos prerenderizados no pueden coexistir, y para aplicaciones empresariales con inicio de sesión, un CSP estricto gana. El almacenamiento en caché de datos con "use cache" aún funciona. No elimines ninguna de las dos mitades sin leer la regla 4 de nextjs-security.

  16. Estilos: SCSS BEM global, importado por el componente. Turbopack compila Sass con el paquete sass; sassOptions.loadPaths: ["src/styles"] hace que @use "abstracts" funcione desde cualquier profundidad. Sin imports ~, sin sassOptions.functions. Reglas en scss-bem.

  17. Imágenes a través de next/image, fuentes a través de next/font. sharp viene con Next para el optimizador; la imagen del runner no necesita paquete adicional. Las imágenes remotas necesitan images.remotePatterns con un nombre de host exacto.

  18. Verifica el tamaño del bundle con pnpm next analyze (el analizador de Turbopack; @next/bundle-analyzer es solo para webpack). Carga bajo demanda los widgets pesados del cliente (editor nuvui, mapas, gráficos debajo del pliegue) con next/dynamic.

  19. Usa rutas tipadas y tipos generados. typedRoutes: true verifica <Link href>; PageProps<"/invoices/[id]"> y LayoutProps son globales después de next typegen (se ejecuta automáticamente con next dev/next build). No escribas manualmente los tipos params.

  20. Sin next lint. Fue eliminado en la versión 16. Biome lint (consulta biome); TypeScript verifica con tsc --noEmit por paquete.

Verificar

pnpm typecheck
pnpm lint
pnpm build                      # turbo run build: falla en errores de prerender, errores de tipo, errores de Sass
pnpm --filter <app> start &     # luego:
curl -fsS localhost:3000/api/health

Fuentes

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

Nuvraxis/nuvraxis-plugins

>- Biome 2.5 setup and rules for Nuvraxis monorepos — root biome.json with pinned $schema, VCS ignore, formatter settings, the recommended preset with a11y and the react/next domains, nursery policy, organize imports, overrides, nested per-package configs ("extends": "//"), biome check --write locally, biome ci in CI, VS Code settings, and migrating from ESLint/Prettier. Use when the repo has biome.json or biome.jsonc, @biomejs/biome in package.json, .eslintrc*/eslint.config.*/.prettierrc* to migrate, or when fixing lint and formatting errors.

Nuvraxis/nuvraxis-plugins

>- Dockerfile rules for Next.js standalone apps in a pnpm + Turborepo monorepo — multi-stage build (turbo prune → pnpm fetch/offline install → turbo build → minimal runner), pinned Node 26 Alpine by digest, checksum-verified pnpm binary, non-root uid 1001, read-only root filesystem with a writable .next/cache, HEALTHCHECK on /api/health, build args only for NEXT_PUBLIC_* values, BuildKit secrets and cache mounts, multi-arch, OCI labels and .dockerignore. Use when the repo has a Dockerfile, .dockerignore, compose file, or next.config with output "standalone", or when asked to containerise, shrink, harden or debug an image.

Nuvraxis/nuvraxis-plugins

>- GitHub Actions conventions for Nuvraxis Next.js apps — exactly three workflows: pr.yaml (every PR to any branch: Biome, stylelint, typecheck/test/build with turbo --affected, Docker build + health check, helm lint + kubeconform; publishes nothing), main.yaml (push to main: one multi-arch image to GHCR tagged sha-SHORTSHA and main, provenance + SBOM, gha cache), release.yaml (tag vX.Y.Z: verify on main, retag the existing image without rebuilding, package and push the Helm chart to OCI, GitHub Release with chart, digest and SBOM). Minimal permissions per job, GITHUB_TOKEN only, pinned action majors. Use when editing .github/workflows/*, adding a CI step, or debugging a failed run or release.

Nuvraxis/nuvraxis-plugins

>- Helm chart rules for Nuvraxis Next.js apps — one chart per app in charts/ (named after the app), published to oci://ghcr.io/nuvraxis/charts and synced by Argo CD; Chart.yaml version/appVersion set only by release.yaml; Deployment with startup/liveness/readiness probes on /api/health, non-root read-only security context, emptyDir for .next/cache, ConfigMap + existing Secret via envFrom, Service, Ingress with cert-manager, HPA, PDB, ServiceAccount, topology spread; no Helm hooks; helm lint --strict + kubeconform. Use when the repo has charts/, Chart.yaml, values*.yaml, templates/*.yaml with Helm syntax, or an Argo CD Application, or when asked to deploy, scale, expose or configure the app on Kubernetes.

Skills relacionados