Introduction
The error “Could Not Parse Module [project]/proxy.ts” can be confusing when you are working with a Next.js application. The message points to proxy.ts, but it does not always explain what is wrong inside the file. In most cases, Next.js cannot read or compile the file because of invalid TypeScript syntax, an incorrect export, an unsupported import, or an incorrect file location.
The problem is also more common when upgrading a project. In current Next.js versions, the older middleware.ts file convention has been renamed to proxy.ts. The logic is similar, but the function and file names need to match the new convention. Next.js runs Proxy code before a request is completed, so it is often used for authentication checks, redirects, rewrites, logging, and request headers. See the official Next.js Proxy documentation for the complete API reference.
This guide explains the most common causes of Could Not Parse Module [project]/proxy.ts and shows practical fixes that beginners can follow.
What Does the Error Mean?
When Next.js says it could not parse proxy.ts, it means the compiler or bundler could not understand the module. The file may contain a syntax error, an invalid export, a misplaced bracket, or code that does not match the Next.js Proxy convention.
The error can happen during next dev, while the development server is starting, or during next build. The exact terminal message may identify a line number. Always check that line first, but also inspect the complete file because an error on an earlier line can make a later line look incorrect.
Starting with Next.js 16, Middleware is called Proxy. The official migration guide explains that the file should change from middleware.ts to proxy.ts, and the exported function should change from middleware to proxy. Read the official Middleware-to-Proxy migration guide when upgrading an existing project.
Step 1: Use a Valid proxy.ts File
Start by replacing the file temporarily with a small, valid example. This helps you determine whether the issue is with the file structure or with your custom logic.
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
export function proxy(request: NextRequest) {
return NextResponse.next()
}Code language: JavaScript (javascript)This example does three simple things:
- Imports the
NextRequesttype. - Imports
NextResponsefromnext/server. - Exports one function named
proxy.
If this file works, the original problem is probably in your previous code. Add your imports and logic again one part at a time. If the minimal file still fails, continue with the file-location and version checks below.
Step 2: Check the File Location
The proxy.ts file must be in the project root, or inside the src folder when your project uses src. It should be at the same level as the app or pages directory.
Correct root structure:
my-next-app/
├── app/
├── public/
├── proxy.ts
├── package.json
├── tsconfig.json
└── next.config.tsCode language: PHP (php)Correct src structure:
my-next-app/
├── src/
│ ├── app/
│ └── proxy.ts
├── public/
├── package.json
└── tsconfig.jsonCode language: PHP (php)Do not place the file inside app/dashboard/proxy.ts, pages/admin/proxy.ts, or another nested route folder. Next.js supports one root Proxy file. If you need different behavior for different routes, keep one proxy.ts file and use conditions or a matcher.
import type { NextRequest } from 'next/server'
export function proxy(request: NextRequest) {
const path = request.nextUrl.pathname
if (path.startsWith('/dashboard')) {
// Dashboard-specific logic
}
if (path.startsWith('/admin')) {
// Admin-specific logic
}
}Code language: JavaScript (javascript)The Next.js nested Proxy error documentation explains why multiple nested Proxy files are not supported.
Step 3: Check the Export Name
One of the most common upgrade mistakes is renaming the file but not renaming the function.
This may be left over from an older Middleware implementation:
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
export function middleware(request: NextRequest) {
return NextResponse.next()
}Code language: JavaScript (javascript)For the current Proxy convention, use this:
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
export function proxy(request: NextRequest) {
return NextResponse.next()
}Code language: JavaScript (javascript)You can also use a default export:
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
export default function proxy(request: NextRequest) {
return NextResponse.next()
}Code language: JavaScript (javascript)Use one Proxy function in the file. Do not export both a named Proxy function and a default Proxy function. The official Proxy reference supports a default export or a named proxy function, with an optional config export.
Step 4: Fix TypeScript Syntax Errors
The message Could Not Parse Module [project]/proxy.ts often comes from a basic syntax problem. Look for the following issues:
- A missing closing brace
} - A missing closing parenthesis
) - A missing quote around a string
- A missing comma in an object
- JSX inside a
.tsfile instead of a.tsxfile - An unfinished
ifstatement - Incorrect TypeScript type syntax
For example, this code is invalid because the if statement is not closed:
export function proxy(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/admin') {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}Code language: JavaScript (javascript)The closing parenthesis is missing after '/admin'. The corrected version is:
export function proxy(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/admin')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}Code language: JavaScript (javascript)Run TypeScript directly to find errors faster:
npx tsc --noEmitYour editor may also underline the exact location of the syntax error. Fix the first error shown before working on later errors.
Step 5: Use Correct Redirect and Rewrite URLs
Redirects and rewrites inside Proxy should use valid absolute URLs. A common mistake is passing a relative string directly to NextResponse.redirect or NextResponse.rewrite.
Avoid this pattern:
return NextResponse.redirect('/login')Code language: JavaScript (javascript)Use the request URL as the base instead:
return NextResponse.redirect(new URL('/login', request.url))Code language: JavaScript (javascript)A complete authentication example looks like this:
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
export function proxy(request: NextRequest) {
const token = request.cookies.get('token')?.value
const pathname = request.nextUrl.pathname
if (pathname.startsWith('/dashboard') && !token) {
const loginUrl = new URL('/login', request.url)
loginUrl.searchParams.set('from', pathname)
return NextResponse.redirect(loginUrl)
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*'],
}Code language: JavaScript (javascript)The Next.js Proxy relative URL guide recommends creating an absolute URL for redirects and rewrites. For complex applications, cloning request.nextUrl can also preserve settings such as basePath and locale configuration.
Step 6: Check the matcher Configuration
The matcher configuration controls which paths run through Proxy. Keep matcher values as static strings or arrays so Next.js can analyze them during the build.
Good example:
export const config = {
matcher: ['/dashboard/:path*', '/profile/:path*'],
}Code language: JavaScript (javascript)Problematic example:
const protectedPath = '/dashboard/:path*'
export const config = {
matcher: protectedPath,
}Code language: JavaScript (javascript)Dynamic matcher values may be ignored because Next.js needs to analyze them statically. Also remember that Proxy without a matcher can run on many requests, including static files and image assets. A redirect or authentication check that accidentally affects CSS, JavaScript, or images can make the entire application appear broken.
Step 7: Review Imports and Runtime Compatibility
Proxy code runs outside the normal React component environment. Avoid importing browser-only values such as window or document, and be careful with server-only packages that are not supported in the Proxy runtime.
Do not write this at the top level:
const currentPath = window.location.pathnameCode language: JavaScript (javascript)Use the request object instead:
export function proxy(request: NextRequest) {
const currentPath = request.nextUrl.pathname
return NextResponse.next()
}Code language: JavaScript (javascript)Also avoid putting database queries, large business rules, or heavy dependencies in Proxy. Use Proxy for an early request decision, then perform secure data checks in your server-side data layer or route handler. This keeps the Proxy file small and reduces build and runtime problems.
Step 8: Check Your Next.js Version and Migrate Carefully
Run this command to see the installed version:
npm list nextCode language: PHP (php)If your project uses an older version, it may still expect middleware.ts. If you are upgrading to a version that uses the Proxy convention, migrate both the filename and function name together.
npx @next/codemod@canary middleware-to-proxy .Code language: CSS (css)After migration, inspect the file manually. Codemods are useful, but you should still check custom imports, matchers, redirects, and authentication logic.
Step 9: Clear the Development Cache and Rebuild
Sometimes the source code is fixed but the development cache still contains an old compilation result. Stop the development server, remove the .next directory, and start it again.
On macOS or Linux:
rm -rf .next
npm run devCode language: CSS (css)On Windows PowerShell:
Remove-Item -Recurse -Force .next
npm run devCode language: CSS (css)Then test a production build:
npm run build
npm run startDo not delete node_modules immediately. First check syntax, exports, file location, imports, and the Next.js version. Reinstall dependencies only when the package installation itself appears damaged.
Best Practices for proxy.ts
Follow these practices to avoid the error in future projects:
- Keep one small root-level
proxy.tsfile. - Export one named
proxyfunction or one default function. - Use
NextRequestandNextResponsefromnext/server. - Keep
matchervalues static. - Use absolute URLs for redirects and rewrites.
- Avoid browser APIs such as
windowanddocument. - Protect static assets from unnecessary authentication logic.
- Run
npx tsc --noEmitbefore committing changes. - Test both
npm run devandnpm run build. - Keep sensitive authorization decisions in secure server-side code, not only in a client-side check.
Common Mistakes
Keeping middleware as the exported function
When using proxy.ts, rename the function to proxy unless you deliberately use the supported default export form.
Creating more than one Proxy file
Do not create separate Proxy files inside multiple route folders. Combine the logic in the root proxy.ts and use matcher values or pathname conditions.
Returning nothing from some branches
Make sure every request reaches a valid response, usually NextResponse.next():
export function proxy(request: NextRequest) {
if (request.nextUrl.pathname === '/old-page') {
return NextResponse.redirect(new URL('/new-page', request.url))
}
return NextResponse.next()
}Code language: JavaScript (javascript)Copying all request headers
Forwarding every header can expose sensitive information or affect framework behavior. If you need to forward headers, create a small allow-list of safe headers. The NextResponse documentation explains the difference between forwarding request headers and sending response headers.
Mixing JSX with TypeScript
proxy.ts is not a React UI component. Keep JSX out of this file. If a UI file contains JSX, use the .tsx extension instead.
Quick Troubleshooting Checklist
Before searching for a more complex solution, check the following:
- Is the file named exactly
proxy.tswith the correct lowercase spelling? - Is it in the project root or the correct
srclocation? - Does it export
proxyor a supported default function? - Is there only one Proxy file?
- Are all braces, parentheses, commas, and quotes closed?
- Are imports coming from valid packages?
- Are redirects and rewrites using absolute URLs?
- Are matcher values static?
- Are you using the correct convention for your installed Next.js version?
- Does
npx tsc --noEmitpass? - Does
npm run buildpass after clearing.next?