מעבר מ-middleware.ts ל-proxy.ts ב-Next.js 16: מדריך מלא עם דוגמאות קוד

Next.js 16 שינה את middleware.ts ל-proxy.ts עם מעבר מ-Edge ל-Node.js Runtime. מדריך מעשי למיגרציה עם codemod, דוגמאות אימות, טעויות נפוצות, וטיפים לארכיטקטורת אבטחה נכונה.

Next.js 16 proxy.ts: מדריך מיגרציה 2026

למה Next.js 16 שינה את השם מ-middleware ל-proxy?

אם עדכנתם לאחרונה ל-Next.js 16, בטח שמתם לב שמשהו השתנה. הקובץ middleware.ts שהכרתם? הוא קיבל שם חדש — proxy.ts. ואני חייב לציין, בהתחלה זה הרגיש כמו שינוי שרירותי, אבל ככל שהעמקתי בנושא, ההיגיון מאחוריו נהיה ברור.

זה לא סתם שינוי קוסמטי. מדובר בשינוי ארכיטקטוני אמיתי שמשפיע על סביבת הריצה, על האפשרויות הזמינות לכם, ועל הדרך שבה כדאי לחשוב על שכבת הבקשות באפליקציה.

הבעיה המרכזית? המונח "middleware" יצר בלבול מתמשך עם Express.js middleware. מפתחים רבים (ולא, אני לא מצביע על אף אחד ספציפי) דחפו לקובץ הזה לוגיקה עסקית מורכבת שפשוט לא הייתה אמורה להיות שם. צוות Next.js החליט שהשם "proxy" משקף טוב יותר את התפקיד האמיתי: שכבת רשת שיושבת מול האפליקציה, ותפקידה לטפל בניתוב, הפניות, ובדיקות ראשוניות — לא יותר מזה.

ההבדלים העיקריים בין middleware.ts ל-proxy.ts

אז מה בעצם השתנה מעבר לשם? ההבדל הכי משמעותי הוא דווקא סביבת הריצה. בואו נסתכל:

תכונהmiddleware.ts (ישן)proxy.ts (חדש)
סטטוסDeprecatedפעיל (v16+)
סביבת ריצהEdge RuntimeNode.js Runtime
תמיכה ב-Edgeכןלא
גישה ל-Node.js APIsמוגבלתמלאה
שינוי Runtimeאפשריקבוע — Node.js בלבד
תמיכה ב-npm packagesמוגבלתמלאה
פריסה גלובליתכן (multi-region)לא (single region)
Cold Startמהיר יותראיטי מעט יותר

מה השינוי ל-Node.js Runtime פותח?

בואו נהיה כנים — הגבלות ה-Edge Runtime ב-middleware.ts היו מתסכלות. חבילות כמו node-postgres או ioredis פשוט לא עבדו שם. עם proxy.ts, נפתח עולם שלם:

  • חיבור ישיר למסדי נתונים (Postgres, MySQL, Redis)
  • קריאה וכתיבה למערכת הקבצים
  • שימוש בכל חבילת npm מהאקוסיסטם של Node.js
  • ספריות אימות מורכבות שדורשות סביבת Node.js מלאה

אבל (ותמיד יש "אבל"), יש trade-off. סביבת Node.js לא מהירה כמו Edge בהפעלה ראשונית, ובדרך כלל היא רצה באזור גיאוגרפי אחד בלבד. אם הביצועים הגלובליים קריטיים עבורכם, זה משהו שכדאי לקחת בחשבון.

מיגרציה אוטומטית עם Codemod

הדרך הכי מהירה לעשות את המעבר? ה-codemod הרשמי. פשוט הריצו:

npx @next/codemod@canary middleware-to-proxy .

וזהו, באמת. ה-codemod מטפל בשני הדברים העיקריים:

  • משנה את שם הקובץ מ-middleware.ts ל-proxy.ts
  • משנה את שם הפונקציה המיוצאת מ-middleware ל-proxy

ברוב המקרים, זה כל מה שצריך. הלוגיקה עצמה נשארת זהה.

מיגרציה ידנית — צעד אחר צעד

מעדיפים שליטה מלאה על התהליך? אין בעיה. הנה איך עושים את זה ידנית:

שלב 1: שינוי שם הקובץ

mv middleware.ts proxy.ts
# או עבור JavaScript
mv middleware.js proxy.js

שלב 2: עדכון הפונקציה המיוצאת

לפני — הגרסה הישנה (middleware.ts):

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const session = request.cookies.get('session');
  if (!session) {
    return NextResponse.redirect(new URL('/login', request.url));
  }
  return NextResponse.next();
}

export const config = {
  matcher: ['/dashboard/:path*'],
};

אחרי — הגרסה החדשה (proxy.ts):

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function proxy(request: NextRequest) {
  const session = request.cookies.get('session');
  if (!session) {
    return NextResponse.redirect(new URL('/login', request.url));
  }
  return NextResponse.next();
}

export const config = {
  matcher: ['/dashboard/:path*'],
};

שמתם לב? ההבדל היחיד הוא שם הפונקציה. שאר הקוד זהה לחלוטין.

שלב 3: עדכון דגלי קונפיגורציה

דבר שקל לפספס — גם חלק מהגדרות הקונפיגורציה שונו. לדוגמה:

  • skipMiddlewareUrlNormalize הפך ל-skipProxyUrlNormalize

אל תשכחו לעדכן גם את next.config.ts בהתאם.

שלב 4: מיקום הקובץ

הקובץ proxy.ts צריך לשבת בשורש הפרויקט, או בתוך תיקיית src אם אתם משתמשים בה — באותה רמה כמו app או pages. וחשוב לדעת: רק קובץ proxy אחד נתמך בפרויקט.

דוגמאות מעשיות ל-proxy.ts

בואו נעבור על כמה דפוסים נפוצים שכנראה תצטרכו ביום-יום:

אימות בסיסי עם בדיקת session cookie

import { NextRequest, NextResponse } from 'next/server';
import { decrypt } from '@/app/lib/session';
import { cookies } from 'next/headers';

const protectedRoutes = ['/dashboard', '/settings', '/profile'];
const publicRoutes = ['/login', '/signup', '/'];

export default async function proxy(req: NextRequest) {
  const path = req.nextUrl.pathname;
  const isProtectedRoute = protectedRoutes.some(route => path.startsWith(route));
  const isPublicRoute = publicRoutes.includes(path);

  const cookie = (await cookies()).get('session')?.value;
  const session = await decrypt(cookie);

  if (isProtectedRoute && !session?.userId) {
    return NextResponse.redirect(new URL('/login', req.nextUrl));
  }

  if (isPublicRoute && session?.userId && !path.startsWith('/dashboard')) {
    return NextResponse.redirect(new URL('/dashboard', req.nextUrl));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|.*\\.png$).*)'],
};

הגנה על נתיבי API

import type { NextRequest } from 'next/server';
import { isAuthenticated } from '@/lib/auth';

export const config = {
  matcher: '/api/:function*',
};

export function proxy(request: NextRequest) {
  if (!isAuthenticated(request)) {
    return Response.json(
      { success: false, message: 'authentication failed' },
      { status: 401 }
    );
  }
}

שימוש עם Better Auth

import { NextRequest, NextResponse } from 'next/server';
import { headers } from 'next/headers';
import { auth } from '@/lib/auth';

export async function proxy(request: NextRequest) {
  const session = await auth.api.getSession({
    headers: await headers()
  });

  if (!session) {
    return NextResponse.redirect(new URL('/sign-in', request.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ['/dashboard/:path*'],
};

ארכיטקטורת אימות נכונה עם proxy.ts

נקודה חשובה שרבים מפספסים: proxy.ts הוא רק השכבה הראשונה באסטרטגיית האבטחה שלכם. הוא לא מספיק בפני עצמו. הגישה המומלצת כוללת שלוש שכבות:

  1. proxy.ts — שכבה ראשונה: בדיקות מהירות ואופטימיסטיות. הפניית משתמשים לא מאומתים, רענון session cookies, חסימת נתיבי auth למשתמשים מחוברים. חשבו על זה כ"שומר בכניסה" — הוא בודק אם יש לכם כרטיס, אבל לא את תוכן התיק.
  2. Server Actions — שכבה שנייה: אימות זהות והרשאות בכל פעולה. לעולם אל תניחו שה-proxy כבר טיפל בזה.
  3. Row Level Security (RLS) — שכבה שלישית: נעילה ברמת מסד הנתונים. גם אם Server Action הוגדר בטעות בצורה רחבה מדי, ה-RLS ימנע דליפת נתונים.

למה זה כל כך חשוב? כי שינוי קטן ב-matcher או ב-routing יכול לבטל בשקט את הכיסוי של ה-proxy. לכן, תמיד וודאו אימות והרשאה בתוך כל Server Function בנפרד.

טעויות נפוצות במיגרציה (ואיך להימנע מהן)

1. שכחת שינוי שם הפונקציה

זו כנראה הטעות הנפוצה ביותר. אנשים משנים את שם הקובץ ושוכחים לשנות את שם הפונקציה. אם הפונקציה המיוצאת עדיין נקראת middleware, היא תמשיך לעבוד — אבל תקבלו אזהרות deprecation שיזהמו לכם את הלוגים. שנו גם את שם הפונקציה ל-proxy.

2. ציפייה ל-Edge Runtime

proxy.ts רץ על Node.js בלבד. נקודה. אם אתם תלויים ב-Edge Runtime (למשל, בשביל latency נמוך בפריסה גלובלית), אפשר להמשיך עם middleware.ts לעת עתה — רק זכרו שהוא deprecated ויוסר בגרסה עתידית.

3. שגיאות פריסה ב-Vercel

כמה מפתחים נתקלו בשגיאה הזו אחרי שדרוג:

Error: ENOENT: no such file or directory, lstat '.../.next/server/proxy.js'

הפתרון פשוט: הריצו את ה-codemod הרשמי כדי לוודא שכל ההפניות עודכנו, ובנו מחדש את הפרויקט לפני הפריסה. לפעמים rm -rf .next ו-build מחדש פותרים את זה.

4. אי-עדכון ספריות צד שלישי

ספריות כמו next-intl כבר עדכנו את התיעוד שלהן לתמוך ב-proxy.ts. אם אתם משתמשים בספריות שמשתלבות עם middleware, בדקו שהגרסאות מעודכנות ושהקונפיגורציה תואמת את המוסכמה החדשה.

מה לגבי CVE-2025-29927?

שווה להזכיר את הפיל שבחדר. במרץ 2025 נחשפה פגיעות קריטית (CVSS 9.1) ב-Next.js middleware. תוקפים יכלו לעקוף את כל לוגיקת ה-middleware באמצעות שליחת header מסוים (x-middleware-subrequest). הפגיעות תוקנה בגרסאות 12.3.5, 13.5.9, 14.2.25 ו-15.2.3.

הלקח הכי חשוב מהסיפור הזה? middleware (ועכשיו proxy) הוא לא גבול אבטחה. הוא שכבת routing ראשונית בלבד. בדיקות האימות האמיתיות חייבות לשבת ב-Route Handlers, Server Actions, ובשכבת הגישה לנתונים.

שאלות נפוצות

האם אפשר להשתמש גם ב-middleware.ts וגם ב-proxy.ts באותו פרויקט?

לא. רק אחד מהם יכול להתקיים. אם שני הקבצים נמצאים בפרויקט, Next.js יתעדף את proxy.ts. ההמלצה שלי: עברו לחלוטין ל-proxy.ts ומחקו את middleware.ts.

האם proxy.ts תומך ב-async/await?

בהחלט. מכיוון ש-proxy.ts רץ על Node.js runtime, יש תמיכה מלאה ב-async/await. זה כולל גישה אסינכרונית ל-cookies() ו-headers() — כפי שנדרש ב-Next.js 16.

מה קורה אם אני צריך Edge Runtime לביצועים?

אם אתם באמת חייבים Edge Runtime לצורך latency נמוך בפריסה גלובלית, תוכלו להמשיך עם middleware.ts לעת עתה. צוות Next.js הודיע שהנחיות נוספות לגבי Edge Runtime יפורסמו בגרסת minor עתידית. שווה לעקוב אחרי ה-changelog.

איך מארגנים לוגיקה מורכבת אם יש רק קובץ proxy אחד?

שאלה מצוינת. למרות שרק קובץ proxy.ts אחד נתמך, אפשר (ואפילו כדאי) לפצל את הלוגיקה למודולים נפרדים ולייבא אותם. למשל, צרו קבצים כמו proxy/auth.ts, proxy/i18n.ts ו-proxy/rate-limit.ts, וייבאו אותם לקובץ הראשי.

האם ה-codemod מטפל גם בקבצי קונפיגורציה?

לא לגמרי. ה-codemod משנה את שם הקובץ ואת שם הפונקציה, אבל שינויים בקובצי קונפיגורציה — כמו skipMiddlewareUrlNormalize ל-skipProxyUrlNormalize — צריך לבצע ידנית. אל תשכחו את השלב הזה.

אודות הכותב Editorial Team

Our team of expert writers and editors.