Czym jest middleware w Next.js i kiedy warto go użyć?
Middleware w Next.js to funkcja uruchamiana przed routingiem dla żądań pasujących do matchera. Od Next.js 16 nowa konwencja proxy.ts działa w runtime Node.js i nie obsługuje konfiguracji runtime: 'edge'. Starsze middleware.ts korzystające z może pozostać tymczasowo podczas migracji, ale nazwa i konwencja są deprecjonowane.
Od Next.js 16 oficjalna nazwa tego mechanizmu to Proxy, a plik konwencji to proxy.ts. W starszych materiałach i istniejących projektach nadal spotkasz nazwę middleware.ts, dlatego w tym artykule używam obu określeń zamiennie.
Proxy definiujesz w jednym pliku proxy.ts w katalogu głównym projektu, a jeśli używasz struktury src/ to wewnątrz src/, na tym samym poziomie co app/. Tylko uwaga, ponieważ plik położony obok src/ zamiast w środku, nie zarejestruje się. Wtedy build przejdzie bez błędu, a proxy nie będzie działać. Plik ten przechwytuje każde żądanie pasujące do skonfigurowanego i pozwala je zmodyfikować, przekierować lub zablokować, jeszcze zanim cokolwiek trafi do klienta.
Matcher jest analizowany statycznie, więc jego wartości muszą być stałymi zapisanymi bezpośrednio w konfiguracji. Nie kopiuj jednego negatywnego regexu do każdego projektu tylko zdecyduj, czy Proxy ma objąć Route Handlery, pliki z kropką w nazwie, metadata routes i prefetch. Każdą taką decyzję musisz pokryć testem unstable_doesProxyMatch.
7 praktycznych zastosowań middleware w Next.js
1. Autoryzacja i ochrona tras w Next.js middleware
Najczęstsze zastosowanie, czyli sprawdzenie, czy użytkownik jest zalogowany, zanim zobaczy chronioną stronę. Zamiast umieszczać logikę auth w każdym layout lub page, centralizujesz ją w middleware.
Samo dekodowanie payloadu JWT za pomocą Base64 nie stanowi weryfikacji, bo atakujący może podmienić exp, rolę i identyfikator, jeśli kod nie sprawdza kryptograficznego podpisu. Dlatego Proxy należy traktować jako optymistyczny filtr i mechanizm poprawiający UX, a nigdy jako jedyną kontrolę. Bezpieczna autoryzacja musi działać blisko danych w warstwie dostępu (DAL), Server Actions i Route Handlerach, uwzględniając przy tym uprawnienia do konkretnego zasobu.
To nie jest jedynie teoria, ponieważ CVE-2025-29927 umożliwiło ominięcie Middleware poprzez spreparowany nagłówek, a w 2026 roku opublikowano kolejne ostrzeżenia dotyczące obejścia Middleware/Proxy w określonych ścieżkach App Routera. Należy regularnie aktualizować Next.js do najnowszego wspieranego wydania i nie opierać bezpieczeństwa na założeniu, że Proxy zawsze zostanie wykonane. Zmiana matchera lub przeniesienie Server Action również może usunąć filtr brzegowy bez modyfikacji samej akcji. Gdy potrzebujesz ról i uprawnień, rozbuduj ten wzorzec według artykułu o RBAC w Next.js — role, uprawnienia i Proxy.
2. Geolokacja w middleware i treść dopasowana do lokalizacji
W Next.js 15 z NextRequest usunięto pola geo i ip, więc geolokację odczytujesz dziś najczęściej z nagłówków dodawanych przez platformę edge. Proxy może je wykorzystać do przekierowań lub ustawienia cookie z lokalizacją.
Nagłówki geolokalizacyjne są rozszerzeniem platformy, a nie Next.js. Na samodzielnym hostingu mogą być nieobecne albo podatne na spoofing, jeśli reverse proxy nie usuwa wartości od klienta. Traktuj kraj jako podpowiedź do wyboru języka, waluty czy oddziału i pozwól użytkownikowi ją zmienić. Nie używaj samego IP jako dowodu rezydencji podatkowej ani jedynej kontroli wymogów prawnych. Dane lokalizacyjne, takie jak nazwa miasta, mogą pojawić się w formie zakodowanej. Należy je defensywnie dekodować, minimalizować ich retencję i zawsze uwzględniać politykę prywatności.
3. A/B testy w Next.js bez zewnętrznych narzędzi
Proxy jest dobrym miejscem do przypisania wariantu przed renderowaniem, jeśli eksperyment dotyczy routingu lub całej odpowiedzi. Pozwala uniknąć migotania treści, ale wymaga kontroli cache, botów, analityki ekspozycji i prywatności.
Nigdy nie umieszczaj w ścieżce niezwalidowanej wartości cookie, która mogłaby spowodować nieoczekiwane przepisywanie adresów (rewrite'y). Wariant przypisuj wyłącznie do tras objętych eksperymentem, pomijając zasoby statyczne, API i boty. Identyfikator eksperymentu i ekspozycję rejestruj dopiero w momencie faktycznego wyświetlenia wariantu, ponieważ samo jego przypisanie nie jest jeszcze konwersją. Pamiętaj, że przepisywanie adresów (rewrite) i użycie plików cookie mogą wpływać na klucz cache, dlatego kluczowe jest przetestowanie, czy warianty nie mieszają się w CDN i czy adres kanoniczny pozostaje publicznym URL-em, a nie wewnętrzną ścieżką typu /variants/....
4. Rate limiting w middleware na poziomie proxy
Limiter musi używać stanu, którego klient nie może wyzerować, i który jest współdzielony przez instancje. Cookie nie spełnia żadnego z tych warunków. Przykład z rozproszonym magazynem może wyglądać tak:
Nie ufaj pierwszej wartości dowolnego x-forwarded-for, dopóki nie znasz łańcucha zaufanych proxy, ponieważ klient może wysłać własny nagłówek. Dla operacji po zalogowaniu lepszy bywa userId, a dla logowania kombinacja IP, konta i szerszych zabezpieczeń anty-bot. Limiter w Proxy chroni szeroki brzeg, ale kosztowne lub finansowe operacje powinny mieć dodatkowy limit w samej Server Action/Route Handlerze. Ustal zachowanie przy awarii magazynu np fail-open dla publicznej treści i fail-closed dla wrażliwej operacji mogą być właściwymi, ale różnymi decyzjami. Pełną implementację pokazuje rate limiting w Next.js z Upstash.
5. Dynamiczne redirecty i rewrite'y w Next.js
Middleware pozwala centralnie zarządzać przekierowaniami bez modyfikowania next.config.ts co jest szczególnie przydatne, gdy lista redirectów pochodzi z CMS lub bazy danych. Poza tym, przy migracji, gdy musisz przepiąć setki starych URL-i, a jak robić to bez utraty pozycji w Google, opisuje migracja z WordPressa na Next.js — redirecty 301 i pozycje SEO.
Dwie rzeczy warto wiedzieć przy tym wzorcu. Po pierwsze, headers i redirects z next.config.ts wykonują się przed Proxy. Statyczne przekierowania trzymaj w konfiguracji, a Proxy zostaw dla mapy dostępnej bez wolnego zapytania do CMS przy każdym requestcie — np. zsynchronizowanej do KV/cache. Po drugie, waliduj origin, protokół, pętle i łańcuchy przekierowań. Dla trwałej zmiany adresu użyj 308; 307 zachowuje metodę przy przekierowaniu tymczasowym. Normalizację trailing slash Next.js wykonuje domyślnie, chyba że ustawisz skipTrailingSlashRedirect.
6. Nagłówki bezpieczeństwa ustawiane w middleware
Stałe nagłówki bezpieczeństwa najprościej ustawić w headers() w next.config.ts albo na reverse proxy i to bez uruchamiania kodu dla każdego requestu. Proxy jest potrzebne, gdy polityka jest zależna od żądania, np. generuje unikalny nonce CSP.
Poprzednia polityka z script-src 'unsafe-inline' dawała XSS znacznie szersze pole i nie była przykładem mocnego CSP. Next.js odczytuje nonce z CSP obecnego w nagłówku żądania, a tę samą politykę trzeba wysłać w odpowiedzi. Nonce wymusza dynamiczne renderowanie objętych stron i wpływa na cache, więc najpierw wdrażaj Content-Security-Policy-Report-Only, analizuj raporty i ogranicz matcher. frame-ancestors 'none' jest współczesną ochroną clickjacking; X-Frame-Options: DENY możesz zachować dla starszych klientów. HSTS dodawaj wyłącznie po HTTPS i po audycie wszystkich subdomen.
7. Logowanie i analytics bez blokowania odpowiedzi
Dzięki API after z next/server (stabilne od Next.js 15.1) możesz zaplanować pracę po zakończeniu odpowiedzi. Platforma musi jednak podtrzymać invocation przez mechanizm zgodny z waitUntil; wsparcie adapterów nie jest automatyczne. after ma limit czasu platformy, uruchamia się również po błędzie i nie jest trwałą kolejką. Używaj go do telemetryki, którą można utracić lub ponowić; zdarzenia biznesowe zapisuj transakcyjnie do outboxa/kolejki przed odpowiedzią.
Nie wysyłaj automatycznie pełnego URL-a, query stringa, cookie, IP ani user-agenta. Mogą zawierać identyfikatory i dane osobowe. Zdefiniuj allowlistę pól, retencję, sampling i podstawę prawną; sekrety oraz nagłówki autoryzacji zawsze redaguj. Jeśli potrzebujesz śladu audytowego dla zmiany danych, zapis best-effort w after jest niewystarczający.
Dobre praktyki i ograniczenia middleware w Next.js
Czego unikać w middleware, żeby nie spowolnić aplikacji
Ciężkich operacji. Nie ma uniwersalnego limitu 50 ms, po prostu mierz budżet p95/p99. Unikaj bazy i zewnętrznego API na ścieżce każdego requestu.
Dużych zależności.
proxy.tsw Next.js 16 działa w Node.js, ale nadal jest granicą sieciową wykonywaną często. Starszemiddleware.tsna Edge ma węższe API. Nie projektuj kodu na przecięciu obu runtime'ów bez testów adaptera. Szerszy kontekst opisuje Edge Runtime w Next.js — kiedy edge, a kiedy Node.Nadmiarowego matchera. Im precyzyjniej zdefiniujesz
matcher, tym mniej niepotrzebnych wywołań middleware.
Wzorzec chain: jak łączyć wiele middleware w Next.js
Gdy masz wiele odpowiedzialności, zamiast jednej rozbudowanej funkcji, stwórz chain:
W poprzednim wariancie każdy krok zwracał NextResponse, co skutkowało zakończeniem łańcucha po pierwszej funkcji, ponieważ NextResponse jest instancją Response. Zgodnie z poprawionym kontraktem, kroki modyfikujące wspólną odpowiedź nie zwracają nic. Tylko przekierowanie, przepisanie lub blokada stanowią odpowiedź terminalną. W przypadku bardziej złożonych operacji przepisywania, jawny pipeline z typami wyników może być korzystniejszym rozwiązaniem.
Proxy w Next.js: dodatkowe możliwości i realne ograniczenia
Lista siedmiu zastosowań nie wyczerpuje tematu, dwa wzorce zasługują na wzmiankę, ponieważ w praktyce ratują konkretne architektury:
-
CORS dla API. Proxy może centralnie obsługiwać żądania preflight i nagłówki dla wielu Route Handlerów. Należy jednak pamiętać, że lista dozwolonych originów, metod i nagłówków musi być wąska. Nie powinno się zwracać dowolnego Origin wraz z credentials, ale zamiast tego dodać Vary: Origin.
-
Multi-tenancy. Przepisanie subdomeny na ścieżkę (np. klient.twoja-apka.pl na /tenants/klient/...) upraszcza routing, ale aby Host należał do dozwolonej domeny, a tenant był mapowany z zaufanej konfiguracji. Ponadto, każda operacja na danych musi nadal wymuszać tenantId, ponieważ samo przepisanie adresu nie zapewnia izolacji danych.
Od Next.js 15.1 proxy da się też testować jednostkowo. Pakiet next/experimental/testing/server udostępnia m.in. unstable_doesProxyMatch do sprawdzenia, czy matcher obejmuje daną ścieżkę, oraz helpery isRewrite i getRewrittenUrl do asercji na wyniku całej funkcji.
Na koniec, sam zespół Next.js rekomenduje traktować Proxy jako ostateczność i nie powinnien być pierwszym wybór. Co ciekawe, zmiana nazwy z „middleware" ma m.in. zniechęcić do upychania tam logiki, którą lepiej obsłużą dedykowane API frameworka: przekierowania w next.config.ts, autoryzacja w Server Components, nagłówki per route. Siedem zastosowań z tego artykułu to sytuacje, w których centralny punkt przed requestem jest korzystne, a jeśli da się coś zrobić bliżej samej trasy to zrób to tam. Nie kombinuj.
