Skip to content

Add NextJsMiddleware #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 44 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,55 +46,59 @@ In development, to simplify the setup and remove the need to a reverse proxy lik

## Setup Next.js URLs (Development Environment)

If you're serving your site under ASGI during development,
use [Django Channels](https://channels.readthedocs.io/en/stable/) and
add `NextJSProxyHttpConsumer`, `NextJSProxyWebsocketConsumer` to `asgi.py` like the following example.

**Note:** We recommend using ASGI and Django Channels,
because it is required for [fast refresh](https://nextjs.org/docs/architecture/fast-refresh) (hot module replacement) to work properly in Nextjs 12+.
Configure your `asgi.py` with `NextJsMiddleware` as shown below:

```python
import os

from django.core.asgi import get_asgi_application
from django.urls import re_path, path

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
django_asgi_app = get_asgi_application()

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django_nextjs.proxy import NextJSProxyHttpConsumer, NextJSProxyWebsocketConsumer

from django.conf import settings
from django_nextjs.asgi import NextJsMiddleware

# put your custom routes here if you need
http_routes = [re_path(r"", django_asgi_app)]
websocket_routers = []
application = NextJsMiddleware(django_asgi_app)
```

if settings.DEBUG:
http_routes.insert(0, re_path(r"^(?:_next|__next|next).*", NextJSProxyHttpConsumer.as_asgi()))
websocket_routers.insert(0, path("_next/webpack-hmr", NextJSProxyWebsocketConsumer.as_asgi()))
The middleware automatically handles routing for Next.js assets and API requests, and supports WebSocket connections for fast refresh to work properly.

You can use `NextJsMiddleware` with any ASGI application.
For example, you can use it with `ProtocolTypeRouter`
if you are using [Django Channels](https://channels.readthedocs.io/en/latest/):

application = ProtocolTypeRouter(
{
# Django's ASGI application to handle traditional HTTP and websocket requests.
"http": URLRouter(http_routes),
"websocket": AuthMiddlewareStack(URLRouter(websocket_routers)),
# ...
}
```python
application = NextJsMiddleware(
ProtocolTypeRouter(
{
"http": django_asgi_app,
"websocket": my_websocket_handler,
# ...
}
)
)
```

Otherwise (if serving under WSGI during development), add the following to the beginning of `urls.py`:
If you're not using ASGI, add the following path to the beginning of `urls.py`:

```python
path("", include("django_nextjs.urls"))
urlpatterns = [
path("", include("django_nextjs.urls")),
...
]
```

**Warning:** If you are serving under ASGI, do NOT add this
to your `urls.py`. It may cause deadlocks.
> [!IMPORTANT]
> Using ASGI is **required**
> for [fast refresh](https://nextjs.org/docs/architecture/fast-refresh)
> to work properly in Next.js 12+.
> Without it, you'll need to manually refresh your browser
> to see changes during development.
>
> To run your ASGI application, you can use an ASGI server
> such as [Daphne](https://github.com/django/daphne)
> or [Uvicorn](https://www.uvicorn.org/).


## Setup Next.js URLs (Production Environment)

Expand Down Expand Up @@ -273,7 +277,7 @@ urlpatterns = [

- If you want to add a file to `public` directory of Next.js,
that file should be in `public/next` subdirectory to work correctly.
- If you're using Django channels, make sure all your middlewares are
- If you're using ASGI, make sure all your middlewares are
[async-capable](https://docs.djangoproject.com/en/dev/topics/http/middleware/#asynchronous-support).
- To avoid "Too many redirects" error, you may need to add `APPEND_SLASH = False` in your Django project's `settings.py`. Also, do not add `/` at the end of nextjs paths in `urls.py`.
- This package does not provide a solution for passing data from Django to Next.js. The Django Rest Framework, GraphQL, or similar solutions should still be used.
Expand All @@ -287,6 +291,7 @@ Default settings:
NEXTJS_SETTINGS = {
"nextjs_server_url": "http://127.0.0.1:3000",
"ensure_csrf_token": True,
"dev_proxy_paths": ["/_next", "/__next", "/next"],
}
```

Expand All @@ -304,6 +309,15 @@ You may need to issue GraphQL POST requests to fetch data in Next.js `getServerS
In this case this option solves the issue,
and as long as `getServerSideProps` functions are side-effect free (i.e., they don't use HTTP unsafe methods or GraphQL mutations), it should be fine from a security perspective. Read more [here](https://docs.djangoproject.com/en/3.2/ref/csrf/#is-posting-an-arbitrary-csrf-token-pair-cookie-and-post-data-a-vulnerability).

### `dev_proxy_paths`

A list of paths that should be proxied to the Next.js server in development mode.

This is useful if you want to use a custom path instead of `/next` inside the `public` directory of Next.js.
For example, if you want to use `/static-next` instead of `/next`, you can set `proxy_paths` to `["/_next", "/__next", "/static-next"]`
and place your static files in `public/static-next` directory of Next.js.
You should also update the production reverse proxy configuration accordingly.

## Contributing

To start development:
Expand Down
2 changes: 1 addition & 1 deletion django_nextjs/app_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
NEXTJS_SETTINGS = getattr(settings, "NEXTJS_SETTINGS", {})

NEXTJS_SERVER_URL = NEXTJS_SETTINGS.get("nextjs_server_url", "http://127.0.0.1:3000")

ENSURE_CSRF_TOKEN = NEXTJS_SETTINGS.get("ensure_csrf_token", True)
DEV_PROXY_PATHS = NEXTJS_SETTINGS.get("dev_proxy_paths", ["/_next", "/__next", "/next"])
Loading
Loading