Skip to content

Memory leak with axios and AbortSignal in middleware in next >=15.4 #84884

Description

@liammcateer

Link to the code that reproduces this issue

https://github.com/liammcateer/next-abort-signal-memory-leak-reproduction

To Reproduce

  1. Run npm install
  2. Build the next app: npm run build
  3. Run the mock server in a separate terminal window: node mockServer.js
  4. Start the next app: npm run start
  5. Make many requests (I do 1,000) to a single page
  6. Take a heap snapshot using kill -USR2 <next-server PID>. You can find the PID by running ps aux | grep "next-server (v15.5.5)"
  7. Open the heap snapshot in chrome dev tools and look for increasing memory
  8. Repeat steps 5-7 with all other pages.

You will notice that /middleware/axios is the only one that increases memory. You can also verify this by leaving the server running for a little bit and noticing that the memory is never returned.

Current vs. Expected behavior

I expect that fetching an API with axios using the AbortSignal should not cause a memory leak.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.3.0: Thu Jan  2 20:24:16 PST 2025; root:xnu-11215.81.4~3/RELEASE_ARM64_T6000
  Available memory (MB): 32768
  Available CPU cores: 8
Binaries:
  Node: 22.14.0
  npm: 10.9.2
  Yarn: 1.22.22
  pnpm: N/A
Relevant Packages:
  next: 15.5.5 // No Next.js version data was found.
  eslint-config-next: 15.5.5
  react: 19.1.0
  react-dom: 19.1.0
  typescript: 5.9.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Middleware

Which stage(s) are affected? (Select all that apply)

next start (local), Other (Deployed)

Additional context

Tested against different canary releases, the first one that introduced the issue is 15.4.0-canary.95. 15.4.0-canary.94 does not have the issue.

When using axios to call an API inside middlware.ts with an AbortSignal, a memory leak appears.
This code will reproduce the issue:

export async function middleware(req: NextRequest) {
  await axios.get('https://<some-api>/', {
    signal: AbortSignal.timeout(1000),
    adapter: 'fetch',
  });

  return NextResponse.next();
}

If the AbortSignal is removed, or fetch is used instead of axios with an AbortSignal, the issue goes away.

In my reproduction, I called the same api using fetch and axios in both middleware.ts and page.tsx. The issue is only present when axios is used in middleware.ts. Each request was made 1000 times.
Here is a screenshot of various heap snapshots taken after each test. You can see that when axios is used in middleware, the problem presents. I also took another snapshot 30 seconds later, and the memory was still not released. I have also taken some snapshots (not shown) where I left the app for 15 mins, and the memory was still not released.
Image
This screenshot shows quite a few (over 2000) {signal,abort} objects hanging around
Image

I understand that calling APIs in middleware is an anti-pattern, however, this used to work previously, so should be reported as a bug. I also understand that there is a workaround to use fetch instead of axios. Our generated API fetching code uses axios, so our team would need to spend some effort to migrate away from axios. We are using axios with the fetch adapter.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    MiddlewareRelated to Next.js Middleware.

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions