django-nextjs

repository·main·Indexed 19 days ago

https://github.com/querateam/django-nextjs

A library that enables a hybrid architecture where Django and Next.js pages coexist seamlessly. It allows developers to gradually migrate frontends to Next.js or add React pages to existing Django projects using a single entry point. Key features include NextJsMiddleware for ASGI servers, the nextjs_page view for URL mapping, and support for injecting Django templates into Next.js HTML responses.

Tokens
2.1K
Snippets
9
Records
10
Agent score
14%

What's inside django-nextjs

  1. Important implementation notes for django-nextjs

    main

    To ensure a stable integration, follow these requirements:

    • Public Files: Place Next.js public files in the public/next subdirectory.
    • Middleware: Ensure all your Django middlewares are async-capable.
    • URL Configuration: Set APPEND_SLASH = False in your Django settings.py to prevent redirect loops. Do not add trailing slashes to your Next.js paths in urls.py.
    • Data Flow: Use an API (like Django REST Framework or GraphQL) to pass data between Django and Next.js.
    • Server Management: This package does not start the Next.js server; you must run npm run dev or npm run start separately.
  2. Install and configure django-nextjs

    main

    To integrate Next.js with Django, install the package via pip and add django_nextjs to your INSTALLED_APPS in Django settings.

    Note: You must use an ASGI server (like Daphne or Uvicorn) and configure your asgi.py with NextJsMiddleware to support Next.js features like fast refresh.

    pip install django-nextjs
    INSTALLED_APPS = [
        ...
        "django_nextjs",
    ]
  3. Configure NextJsMiddleware in asgi.py

    main

    Wrap your Django ASGI application with NextJsMiddleware. This middleware handles routing for Next.js assets and API requests, and supports WebSockets for fast refresh.

    If you are using Django Channels, you can wrap a ProtocolTypeRouter instead.

    import os
    from django.core.asgi import get_asgi_application
    
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
    django_asgi_app = get_asgi_application()
    
    from django_nextjs.asgi import NextJsMiddleware
    
    application = NextJsMiddleware(django_asgi_app)

    With Django Channels:

    application = NextJsMiddleware(
        ProtocolTypeRouter(
            {
                "http": django_asgi_app,
                "websocket": my_websocket_handler,
                # ...
            }
        )
    )
  4. Setup Next.js URLs in production with Nginx

    main

    In production, you can optimize performance by serving the /_next/static directory directly via Nginx. This avoids routing static asset requests through the Django application server.

    # Replace NEXTJS_PATH with the actual path to your Next.js project
    location /_next/static/ {
        alias NEXTJS_PATH/.next/static/;
        add_header Cache-Control "public, max-age=31536000, immutable";
    }
  5. Customize Next.js HTML responses with Django templates

    main

    You can inject Django templates (like navbars or footers) into the HTML returned by Next.js.

    Warning: This is not compatible with the Next.js App Router. You must set stream=False in nextjs_page() to use this feature.

    1. Update Next.js _document

    Modify pages/_document.jsx (or .tsx) to include specific IDs that django-nextjs uses to inject content:

    <body id="__django_nextjs_body">
      <div id="__django_nextjs_body_begin" />
      <Main />
      <NextScript />
      <div id="__django_nextjs_body_end" />
    </body>

    2. Create the Django Template

    Extend django_nextjs/document_base.html and use the head and body blocks:

    {% extends "django_nextjs/document_base.html" %}
    
    {% block head %}
      {{ block.super }}
    {% endblock %}
    
    {% block body %}
      {% include "navbar.html" %}
      {{ block.super }}
      {% include "footer.html" %}
    {% endblock %}

    3. Use the template in your view

    Pass the template_name to nextjs_page():

    path("/my/page", nextjs_page(template_name="path/to/template.html"), name="my_page"),
    from django_nextjs.views import nextjs_page
    
    urlpatterns = [
        path("/my/page", nextjs_page(template_name="path/to/template.html"), name="my_page"),
    ]
  6. Configure Nginx for Next.js production deployment

    main

    In production, you must use a reverse proxy to route specific URL patterns to your Next.js server and to serve static files.

    • /_next/...: Proxy these requests to your Next.js server (e.g., http://127.0.0.1:3000).
    • /next/...: Serve the contents of the NEXTJS_PATH/public/next directory.
    • /_next/static/... (Optional): You can optimize performance by serving these directly via Nginx with long-lived cache headers.
    location /_next/ {
        proxy_pass  http://127.0.0.1:3000;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    location /next/ {
        alias NEXTJS_PATH/public/next/;
        add_header Cache-Control "public, max-age=0";
    }
    # You can optionally serve "/_next/static" directly by nginx.
    # location /_next/static/ {
    #     alias NEXTJS_PATH/.next/static/;
    #     add_header Cache-Control "public, max-age=31536000, immutable";
    # }
  7. Configure django-nextjs settings

    main

    Configure django-nextjs by defining the NEXTJS_SETTINGS dictionary in your Django settings file. This allows you to specify the Next.js server URL, CSRF token handling, and the public subdirectory path.

    NEXTJS_SETTINGS = {
        "nextjs_server_url": "http://127.0.0.1:3000",
        "ensure_csrf_token": True,
        "public_subdirectory": "/next",
    }
  8. Define Next.js pages in Django URLs

    main

    Use the nextjs_page view to map Django URL paths to Next.js pages.

    If you are using the Next.js App Router, it is highly recommended to set stream=True to enable HTML streaming, which allows for instant loading states.

    from django_nextjs.views import nextjs_page
    
    urlpatterns = [
        path("/my/page", nextjs_page(), name="my_page"),
    
        # With App Router streaming (recommended)
        path("/other/page", nextjs_page(stream=True), name="other_page"),
    ]
  9. Reference: NEXTJS_SETTINGS configuration keys

    main

    The following keys are available within the NEXTJS_SETTINGS dictionary:

    • nextjs_server_url: The URL of the Next.js server (typically started via npm run dev or npm run start).
    • ensure_csrf_token: A boolean. If True, Django ensures a CSRF token is generated and included in the initial request to the Next.js server using django.middleware.csrf.get_token. This is useful for preventing GraphQL POST request failures in getServerSideProps when a user's first request lacks a CSRF cookie.
    • public_subdirectory: A string defining a custom path for the Next.js public directory (defaults to /next). If changed, you must update your production reverse proxy configuration to match.
    NEXTJS_SETTINGS = {
        "nextjs_server_url": "string",
        "ensure_csrf_token": bool,
        "public_subdirectory": "string",
    }