npm.io
2.1.441 • Published 3d agoCLI

@djangocfg/nextjs

Licence
MIT
Version
2.1.441
Deps
8
Size
938 kB
Vulns
0
Weekly
1.4K

@djangocfg/nextjs

@djangocfg/nextjs

Server-side Next.js utilities: OG images, sitemap, health checks, i18n, PWA, navigation, and config

npm version License: MIT

Part of DjangoCFG — a modern Django framework for building production-ready SaaS applications. All @djangocfg/* packages are designed to work together, providing type-safe configuration, real-time features, and beautiful admin interfaces out of the box.


Overview

@djangocfg/nextjs provides server-side utilities for Next.js applications built on top of Django-CFG.

Note: Client components (legal pages, error pages, redirect components) are in @djangocfg/layouts.

Features

  • Page Metadata + OG Images — one factory for complete page metadata; static or dynamically-rendered OG images via Django's django_ogimage (@djangocfg/nextjs/og-image)
  • i18n — full next-intl integration with routing, middleware, and components
  • PWA — zero-config service worker and manifest
  • Base Next.js Config — reusable createBaseNextConfig() factory for monorepos
  • Security headers + CSP — baseline Content-Security-Policy and hardening headers on every route, dev-aware (see below)
  • DPoP auth — one-flag opt-in to RFC 9449 sender-constrained tokens (dpop: true) — see @docs/DPOP.md
  • Sitemap — paginated sitemap-index backed by django_cfg.modules.django_sitemap (handles 2M+ URLs)
  • Health Checks — production-ready health monitoring endpoints
  • Navigation — route definitions, menu generation, and active-state helpers
  • AI Documentation — search DjangoCFG docs via MCP server and CLI

Installation

npm install @djangocfg/nextjs
# or
pnpm add @djangocfg/nextjs
# or
yarn add @djangocfg/nextjs

Quick Start

Search DjangoCFG documentation from the terminal:

# CLI (works anywhere via npx)
npx @djangocfg/nextjs ai-docs search "database configuration"
npx @djangocfg/nextjs ai-docs mcp

Or use the TypeScript API:

import { search, getDocs, getMcpConfig } from '@djangocfg/nextjs/ai';

// Search documentation
const results = await search('database configuration');
results.forEach(r => console.log(r.title, r.url));

// Get formatted docs
const docs = await getDocs('How to configure PostgreSQL?');

// Get MCP server config for AI assistants
const config = getMcpConfig();
MCP Server for AI Assistants

Add to your AI assistant configuration:

{
  "mcpServers": {
    "djangocfg-docs": {
      "url": "https://mcp.djangocfg.com/mcp"
    }
  }
}
Base Next.js Configuration

Create a reusable base configuration for all your Next.js projects:

// next.config.ts
import { createBaseNextConfig } from '@djangocfg/nextjs/config';
import bundleAnalyzer from '@next/bundle-analyzer';

const withBundleAnalyzer = bundleAnalyzer({
  enabled: process.env.ANALYZE === 'true',
});

export default withBundleAnalyzer(createBaseNextConfig({
  // Base path for static builds
  basePath: process.env.NEXT_PUBLIC_STATIC_BUILD === 'true' ? '/cfg/admin' : undefined,
  
  // Add custom transpile packages
  transpilePackages: ['my-custom-package'],
  
  // Custom webpack configuration (called after base webpack logic)
  webpack: (config, options) => {
    // Your custom webpack rules
    return config;
  },
}));
Security headers & CSP

createBaseNextConfig() adds baseline security headers to every route out of the box — no setup required:

  • Content-Security-Policy — a pragmatic baseline that blocks the high-value injection vectors (object-src 'none', base-uri 'self', form-action 'self', frame-ancestors) while keeping the inline/eval scripts a Next.js app needs. Dev-aware: connect-src/img-src allow http:/ws: in development (local Django/Centrifugo) and tighten to https:/wss: only in production.
  • X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin
  • X-Frame-Options: DENY (or SAMEORIGIN when allowIframeFrom is set)

A fully strict nonce-based script-src is a planned follow-up (needs middleware + per-request nonce). To allow iframe embedding, pass allowIframeFrom: ['https://example.com'].

DPoP — sender-constrained tokens (RFC 9449)

Make a stolen access token useless, without a BFF/proxy — opt in with one flag:

export default createBaseNextConfig({
  dpop: true, // inlines NEXT_PUBLIC_DPOP_ENABLED='true'
});

The browser holds a non-extractable key and signs a per-request DPoP proof; the backend binds the token to that key (cnf.jkt) and rejects replays. Requires JWTConfig(dpop_enabled=True) on the Django side. Full guide: @docs/DPOP.md.

PWA (Progressive Web App)

Zero-config PWA - Works out of the box! Service worker and offline support included automatically.

1. Create manifest
// app/manifest.ts
import { createManifest, createScreenshots } from '@djangocfg/nextjs/config';
import { settings } from '@core/settings';

export default createManifest({
  name: settings.app.name,
  description: settings.app.description,
  themeColor: '#ffffff',
  backgroundColor: '#000000',
  icons: {
    logo192: settings.app.icons.logo192,
    logo384: settings.app.icons.logo384,
    logo512: settings.app.icons.logo512,
  },
  // Optional: Add screenshots for Richer PWA Install UI
  // IMPORTANT: Image dimensions must match sizes parameter!
  // screenshots: createScreenshots([
  //   '/screenshots/desktop-1920x1080.png',  // Wide: 1920x1080
  //   '/screenshots/mobile-390x844.png',     // Narrow: 390x844
  // ]),
});
2. Add manifest metadata
// app/layout.tsx
import { createManifestMetadata } from '@djangocfg/nextjs/config';

export const metadata = {
  ...createManifestMetadata({
    name: 'My App',
    themeColor: '#000000',
  }),
};

That's it! PWA is now enabled in production. Generated files:

  • /manifest.webmanifest - From app/manifest.ts
  • /sw.js - Service worker (auto-generated in production)
  • /workbox-*.js - Workbox runtime

Customization (optional):

// next.config.ts
export default createBaseNextConfig({
  pwa: {
    dest: 'public',
    disable: process.env.NODE_ENV === 'development', // Disable in dev
    fallbacks: {
      document: '/_offline', // Offline page
    },
    runtimeCaching: [
      // Custom caching rules
      ...defaultRuntimeCaching,
      createApiCacheRule('https://api.example.com'),
    ],
  },
});

See PWA.md for complete guide.

i18n (Internationalization)

Full next-intl integration for multilingual Next.js apps.

Important: Use subpath imports to avoid React Context issues in server components:

  • @djangocfg/nextjs/i18n - Types only
  • @djangocfg/nextjs/i18n/routing - routing, createRouting, generateLocaleParams
  • @djangocfg/nextjs/i18n/client - I18nProvider, hooks
  • @djangocfg/nextjs/i18n/components - LocaleSwitcher
1. Create middleware (proxy.ts)
// proxy.ts (or middleware.ts)
import createMiddleware from 'next-intl/middleware';
import { routing } from '@djangocfg/nextjs/i18n/routing';

export default createMiddleware(routing);

export const config = {
  matcher: ['/((?!api|_next|_vercel|.*\\..*).*)',],
};
2. Create i18n request config
// i18n/request.ts
import { getRequestConfig } from 'next-intl/server';
import { en, ru, ko } from '@djangocfg/i18n/locales';
import { mergeTranslations } from '@djangocfg/i18n/utils';

const locales = {
  en: mergeTranslations(en, { app: appEn }),
  ru: mergeTranslations(ru, { app: appRu }),
  ko: mergeTranslations(ko, { app: appKo }),
};

export default getRequestConfig(async ({ requestLocale }) => {
  let locale = await requestLocale;
  if (!locale || !(locale in locales)) locale = 'en';

  return {
    locale,
    messages: locales[locale],
    timeZone: 'UTC',
  };
});
3. Use in layout
// app/[locale]/layout.tsx
import { getMessages } from 'next-intl/server';
import { I18nProvider } from '@djangocfg/nextjs/i18n/client';
import { routing, generateLocaleParams } from '@djangocfg/nextjs/i18n/routing';

export function generateStaticParams() {
  return generateLocaleParams();
}

export default async function LocaleLayout({ children, params }) {
  const { locale } = await params;
  const messages = await getMessages();

  return (
    <I18nProvider locale={locale} messages={messages}>
      {children}
    </I18nProvider>
  );
}
4. Use translations in components
'use client';
import { useTranslations } from 'next-intl';

function MyComponent() {
  const t = useTranslations('app');
  return <h1>{t('title')}</h1>;
}
Locale Switcher

Smart wrapper around @djangocfg/layouts LocaleSwitcher with automatic next-intl hooks:

import { LocaleSwitcher } from '@djangocfg/nextjs/i18n/components';

// Basic usage (automatically gets locale from next-intl)
<LocaleSwitcher />

// With custom locales (override routing config)
<LocaleSwitcher locales={['en', 'ru']} />

// With custom labels and styling
<LocaleSwitcher
  labels={{ en: 'English', ru: 'Русский' }}
  variant="outline"
  size="sm"
/>

Note: This component wraps @djangocfg/layouts LocaleSwitcher with useLocaleSwitcher() hook. For a presentational version that accepts locale data via props, use LocaleSwitcher from @djangocfg/layouts directly.

Sitemap Generation

Paginated sitemap-index integrated with django_cfg.modules.django_sitemap. Backed by a typed JSON contract: Django streams keyset-paginated chunks, Next.js's native generateSitemaps() turns each chunk into one XML file plus an auto-generated <sitemapindex> at /sitemap.xml. Handles catalogs up to Google's 50 000-URLs-per-file cap without materialising data on the frontend.

// app/sitemap.ts
import { createDjangoSitemap } from '@djangocfg/nextjs/sitemap';

const { generateSitemaps, sitemap } = createDjangoSitemap({
  host: process.env.NEXT_PUBLIC_SITE_URL!,
  apiUrl: process.env.NEXT_PUBLIC_API_URL,  // optional — omit for static-only
  staticRoutes: [
    { path: '/', changeFrequency: 'daily', priority: 1.0 },
    { path: '/catalog', changeFrequency: 'daily', priority: 0.9 },
  ],
});

export { generateSitemaps, sitemap as default };
export const revalidate = 3600;
// app/robots.ts
import { createRobots } from '@djangocfg/nextjs/sitemap';

export default createRobots({
  host: process.env.NEXT_PUBLIC_SITE_URL!,
  disallow: ['/account/', '/auth', '/api/'],
});

See src/sitemap/README.md for the full backend frontend integration guide, including the Django source registration, cache layers, and deployment notes.

Health Check Endpoint

Create a health monitoring endpoint:

// app/api/health/route.ts
import { createHealthHandler } from '@djangocfg/nextjs/health';

export const GET = createHealthHandler({
  version: process.env.NEXT_PUBLIC_APP_VERSION || '1.0.0',
  checks: [
    {
      name: 'database',
      check: async () => {
        // Check database connection
        return await checkDatabase();
      },
    },
  ],
});
Page Metadata + OG Images

One factory per app builds complete page Metadata (title, openGraph, twitter, canonical + hreflang, icons). The OG image is chosen by a single og field — static brand image by default, dynamic title-rendered card on demand. No Edge Runtime, no @vercel/og:

// app/_core/metadata.ts — bind once
import { makeMetadataFactory } from '@djangocfg/nextjs/og-image'
export const createMetadata = makeMetadataFactory({
  name: settings.app.name,
  description: settings.app.description,
  siteUrl: settings.app.siteUrl,
  ogImage: settings.app.media.ogimage,
  locales: LOCALES,
})

// landing page → static brand image (default)
export const metadata = createMetadata({ title: 'Pricing', path: '/pricing' })
// content page → render the title onto the card
export const metadata = createMetadata({ title: post.title, path, og: 'dynamic' })

The dynamic URL is resolved automatically from NEXT_PUBLIC_MEDIA_URLNEXT_PUBLIC_API_URLNEXT_PUBLIC_SITE_URL. Django renders and caches the PNG — no Edge Runtime or @vercel/og required.

Navigation Utilities

Define routes and generate navigation menus:

import { defineRoute, routesToMenuItems } from '@djangocfg/nextjs/navigation';

const routes = [
  defineRoute('/dashboard', { title: 'Dashboard' }),
  defineRoute('/settings', { title: 'Settings' }),
];

const menuItems = routesToMenuItems(routes);
Client Components

Client-side components (legal pages, error pages, redirect components) are available in @djangocfg/layouts:

// Legal pages
import { PrivacyPage, TermsPage } from '@djangocfg/layouts/pages/legal';

// Error pages
import { ErrorLayout } from '@djangocfg/layouts/components/errors';

// Redirect component
import { RedirectPage } from '@djangocfg/layouts/components/RedirectPage';

Exports

Path Description
@djangocfg/nextjs Main exports (all modules)
@djangocfg/nextjs/i18n Types only (safe for server components)
@djangocfg/nextjs/i18n/routing routing, createRouting, generateLocaleParams, DEFAULT_LOCALES, DEFAULT_LOCALE
@djangocfg/nextjs/i18n/client I18nProvider, hooks ('use client')
@djangocfg/nextjs/i18n/server Server-side i18n utilities
@djangocfg/nextjs/i18n/components LocaleSwitcher ('use client')
@djangocfg/nextjs/i18n/proxy createProxy for middleware
@djangocfg/nextjs/i18n/navigation Link, redirect, usePathname, useRouter
@djangocfg/nextjs/ai AI documentation search and MCP config
@djangocfg/nextjs/config Base Next.js configuration factory
@djangocfg/nextjs/pwa PWA client utilities (service worker registration)
@djangocfg/nextjs/pwa/worker Service worker creation helpers
@djangocfg/nextjs/sitemap Sitemap generation with i18n hreflang support
@djangocfg/nextjs/health Health check handlers
@djangocfg/nextjs/og-image Page metadata factory + static/dynamic OG images for Django's django_ogimage
@djangocfg/nextjs/navigation Route definitions, menu generation, navigation helpers

API Reference

Base Configuration
createBaseNextConfig(options)

Creates a reusable base Next.js configuration with standard DjangoCFG settings.

createBaseNextConfig({
  basePath?: string;                    // Base path for static builds
  transpilePackages?: string[];          // Additional packages to transpile
  optimizePackageImports?: string[];     // Additional packages to optimize
  webpack?: (config, options) => config; // Custom webpack configuration
  experimental?: NextConfig['experimental']; // Custom experimental options
  env?: Record<string, string>;         // Custom environment variables
  // ... any other NextConfig options
})

Features:

  • Automatic dev/production optimizations
  • Filesystem caching for faster rebuilds
  • Compression plugins for static builds (Gzip + Brotli)
  • Standard transpile packages for monorepo
  • Type-safe configuration merging
i18n

Subpath imports required - see table below for correct import paths.

DEFAULT_LOCALES / DEFAULT_LOCALE

All 17 supported locales and the default locale constant.

import { DEFAULT_LOCALES, DEFAULT_LOCALE } from '@djangocfg/nextjs/i18n/routing';

DEFAULT_LOCALES  // ['en', 'ru', 'ko', 'ja', 'de', 'fr', 'zh', 'it', 'es', 'nl', 'ar', 'tr', 'pt-BR', 'pl', 'sv', 'no', 'da']
DEFAULT_LOCALE   // 'en'

Use in locales.config.ts to stay in sync with the package:

// i18n/locales.config.ts
export { DEFAULT_LOCALES as LOCALES, DEFAULT_LOCALE } from '@djangocfg/nextjs/i18n/routing';
export type { LocaleCode as AppLocale } from '@djangocfg/nextjs/i18n';
routing

Default routing configuration with all 17 locales and default locale 'en'.

import { routing } from '@djangocfg/nextjs/i18n/routing';

routing.locales       // ['en', 'ru', 'ko', 'ja', ...]
routing.defaultLocale // 'en'
createRouting(config?)

Create custom routing configuration.

import { createRouting } from '@djangocfg/nextjs/i18n/routing';

const routing = createRouting({
  locales: ['en', 'de', 'fr'],
  defaultLocale: 'en',
  localePrefix: 'always', // 'always' | 'as-needed' | 'never'
});
I18nProvider

Provider component for next-intl integration (client component).

import { I18nProvider } from '@djangocfg/nextjs/i18n/client';

<I18nProvider locale="en" messages={messages}>
  {children}
</I18nProvider>
LocaleSwitcher

Smart locale switcher that wraps @djangocfg/layouts LocaleSwitcher with next-intl hooks.

import { LocaleSwitcher } from '@djangocfg/nextjs/i18n/components';

// Automatically gets locale from next-intl routing
<LocaleSwitcher />

// With custom options
<LocaleSwitcher
  locales={['en', 'ru']}        // Override available locales
  labels={{ en: 'EN', ru: 'RU' }} // Custom locale labels
  variant="outline"
  size="sm"
  showIcon={true}
  className="w-full"
/>

Props (extends @djangocfg/layouts LocaleSwitcherProps):

Prop Type Default Description
locales string[] From routing Override available locales
labels Record<string, string> Built-in Custom locale labels
showCode boolean false Show locale code with label
variant 'ghost' | 'outline' | 'default' 'ghost' Button variant
size 'sm' | 'default' | 'lg' | 'icon' 'sm' Button size
showIcon boolean true Show globe icon
Sitemap
createSitemapHandler(options)

Creates a Next.js route handler for sitemap generation with optional i18n support.

createSitemapHandler({
  siteUrl: string;
  staticPages?: SitemapUrl[];
  dynamicPages?: SitemapUrl[] | (() => Promise<SitemapUrl[]>);
  cacheControl?: string;
  // i18n support
  i18n?: {
    locales: string[];      // e.g., ['en', 'ru', 'ko']
    defaultLocale: string;  // e.g., 'en'
  };
})

When i18n is provided:

  • URLs are expanded for each locale (e.g., /about/en/about, /ru/about, /ko/about)
  • xhtml:link elements with hreflang are added for SEO
  • x-default points to the default locale
Health
createHealthHandler(config)

Creates a health check route handler.

createHealthHandler({
  version?: string;
  checks?: Array<{ name: string; check: () => Promise<boolean> }>;
  customData?: Record<string, any>;
})
Page Metadata + OG Image

@djangocfg/nextjs/og-image builds complete page metadata and OG images for Django's django_ogimage renderer. No Edge Runtime, no @vercel/og, no JSX templates — Django renders and caches the PNG.

See src/og-image/README.md for full docs (the og axis, SiteMetaConfig/PageMeta fields, URL resolution, deployment examples).

Binds a SiteMetaConfig once; returns a per-page factory. The OG image is set by the single og field: 'static' (default) · 'dynamic' · { render } · { image, alt? }.

import { makeMetadataFactory } from '@djangocfg/nextjs/og-image'

export const createMetadata = makeMetadataFactory({
  name: 'CMDOP', description: '', siteUrl: 'https://cmdop.com',
  ogImage: '/static/ogimage.png', locales: LOCALES,
})

export const metadata = createMetadata({ title: 'About', path: '/about' })          // static
export const metadata = createMetadata({ title: post.title, path, og: 'dynamic' })  // rendered title
Low-level (escape hatches)

withOgImage(metadata, params) merges a dynamic OG image into existing metadata; createOgMetadata(params) returns the { openGraph, twitter } fragment; buildOgUrl(params) returns the raw URL string; resolveOgImage(spec, …) is the OgSpec decision point. Most pages use createMetadata and never touch these.

import { buildOgUrl } from '@djangocfg/nextjs/og-image'
const url = buildOgUrl({ title: 'Hello', preset: 'DARK_BLUE' })

URL resolution (NEXT_PUBLIC_MEDIA_URLNEXT_PUBLIC_API_URLNEXT_PUBLIC_SITE_URL → relative).

Navigation
defineRoute(path, metadata, config?)

Defines a route with metadata.

defineRoute('/dashboard', {
  title: 'Dashboard',
  description: 'Dashboard overview',
}, {
  basePath: '/admin',
  isStaticBuild: false,
})
isActive(current, target, allRoutes?)

Checks if a route is currently active.

isActive('/admin/dashboard', '/admin/dashboard') // true
isActive('/admin/dashboard/settings', '/admin/dashboard') // true
isActive('/admin/dashboard', '/admin/settings') // false
routesToMenuItems(routes)

Converts route definitions to menu items.

const menuItems = routesToMenuItems(allRoutes);

Requirements

  • Next.js >= 13.0.0 (App Router)
  • React >= 18.0.0
  • TypeScript >= 5.0.0

Peer Dependencies

  • next - Next.js framework (^15.5.7)

Documentation

Full documentation available at djangocfg.com

Contributing

Issues and pull requests are welcome at GitHub

License

MIT - see LICENSE for details

Keywords