next-auth: Server-side HTTP requests via `getSession` usually get extremely slow on Vercel

Describe the bug

Before further ado, here’s a comparison between a /api/user/{id} request which fetches /api/auth/session through the network even on the server side, versus a /api/site/{id} call, which isn’t protected via getSession. Unfortunately, there’s a quite large margin between response times.

image

Steps to reproduce Call getSession on the server side and observe that it makes an HTTP request instead of just calling functions locally.

Expected behavior Calls to getSession should be executed locally in a server environment. A separate getServerSession method could be added as a non-isomorphic solution without any HTTP calls.

Additional context According to the official Next.js docs:

You should not use fetch() to call an API route in getServerSideProps. Instead, directly import the logic used inside your API route. You may need to slightly refactor your code for this approach.

Fetching from an external API is fine!

This seems to hurt performance badly.

Feedback Documentation refers to searching through online documentation, code comments and issue history. The example project refers to next-auth-example.

  • Found the documentation helpful
  • Found documentation but was incomplete
  • Could not find relevant documentation
  • Found the example project helpful
  • Did not find the example project helpful

Thank you for maintaining this wonderful library – it really helps a lot! 🙏

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 9
  • Comments: 30 (17 by maintainers)

Most upvoted comments

TLDR

  • This has resulted in a 100% (2X) speedup for basically every action in my application
  • Here’s source code for my habit tracking app which is now exclusively using getServerSession and runs on vercel serverless api functions

Here’s my write up of changing to use getServerSession solely in my application

Just as an update to other who are interested in the getServerSession method in regards to implementation and possible performance gains when running serverless on Vercel

I use NextAuth heavily in my open source daily habit tracking application which uses Next (Full SSR Frontend + API) + NextAuth + Prisma + Postgres and is hosted on Vercel. This means all of my API functions are deployed as server less functions and I do all of my auth checking in server side rendering methods for my pages.

Previously NextAuth’s use of http fetch in the getSession method severely hurt performance when run on vercel’s serverless functions – imagine the following flow and the amount of HTTP requests that were happening on Vercel’s platform where HTTP request startup time is the largest hindrance for performance

  1. User that’s already logged in navigates to habitapper.com (1)
    • http request (1)
  2. SSR for page does fetch request for session (2) -> finds a valid session -> redirects user to habitapper.com/habits page
    • http request (2)
  3. User loads habitapper.com/habits (3) -> SSR does fetch request for session (4) -> finds session -> uses internal method (non-http) to get habits for that user and passes them in props to component
    • http requests (3, 4)

With the new getServerSession this removes http requests (2) and (4) because the SSR method is directly accessing the logic to retrieve the session without having to make an http request.

Some notes about current implementation if you’re looking to do this in your application

  1. I had to use next-auth@0.0.0-pr.3222.41318883, when I tried using the getServerSession method with next-auth@4.0.0-beta.7 every call failed to fetch the session and I got errors in console – these went away when I upgraded to this experimental version and I assume will be fixed in auth@4.0.0-beta.8 when it’s released
  2. You’ll need to modify your pages/api/[...nextauth].ts file so you can access the NextAuthOptions object which you’ll need to export and use anywhere you want to use the getServerSession method
  3. Using getServerSession in a server side rendering function differs from using it in api route

@walid-mokrani looks promising, would you care to open a PR against our next branch? I’m pretty sure we could tune it a bit and make it part of the v4 release!

You can see the original comment what I used to base my answers on protecting our current implementation: https://github.com/nextauthjs/next-auth/issues/947#issuecomment-762150858 but I’m getting more and more convinced that this has indeed been a poor choice, especially when the reason behind it was to better support serverless environments. It seems to me that it kind of has the opposite effect of what the original implementation wanted to achieve.

I have created a branch https://github.com/walid-mokrani/next-auth/tree/feat/get-server-side if someone can look at it.

We’ve been using the proposed getServerSession API at Copyfolio for the past few weeks, and since then, our response times have improved greatly.

I would love to see a similar API implemented in the upcoming versions of NextAuth, as it improves performance by a leap in serverless environments.

getServerSession has landed in an experimental release which is going to be included in v4! You can find it here right now: https://github.com/nextauthjs/next-auth/pull/2857#issuecomment-930139134

Documentation comes later, but have a look at these files to get the idea:

https://github.com/nextauthjs/next-auth/blob/9aba57396c6776642ed743b60a266a29385652ac/app/pages/api/auth/[...nextauth].ts image

https://github.com/nextauthjs/next-auth/blob/9aba57396c6776642ed743b60a266a29385652ac/app/pages/protected-ssr.js image

The API is not necessarily final yet, we might change the name or recommend the config to be moved to a next-auth.config.ts file or similar, but it should not really matter.

I think developers should have a choice between the isomorphic and a server-only variant of getSession, getProviders, etc. They should possible be called getServerSession and getServerProviders, respectively.

I think something like this is reasonable in principle but we’d need to address how passing app configuration is handled in a consistent way in different environments (i.e. consistant behaviour that allows for, but doesn’t assume, shared context for all functions).

I’ve got ideas about how I’d like config to work the longer term, but I’m open to suggestions for interim solutions.

There won’t be beta.8. Next stop is at stable v4. 😊

getServerSession won’t launch officially yet, and considered experimental until documented, but hearing that it helped is awesome!

I created a temporary version at 3.22.0-canary.2

import {getServerSession} from "next-auth"
import {options} from "pages/api/auth/[...nextauth]"
export default Page(){
  return null
}
export async function getServerSideProps(context) {
  return {
    props: {
      session: await getServerSession(context, options),
    },
  }
}

And in your [...nextauth].js you have to extract the options into its own const, so you can share it in the page file. This configuration could ultimately be extracted into something like next-auth.config.js or similar I guess, but this is a Work In Progress for now.

Very interested if someone could check out if it helps. The getServerSession does not do fetch

Hi everyone! getServerSession (see above in this thread) has been introduced, which shows very good results, so I consider this issue solved. I opened a new issue that would cover the documentation of it: #3973

As a note, since undocumented, I still consider the feature experimental, and we might change the API when we finalize it.

Cheers 🍻

@trentprynn Ah this was exactly it! Now it’s working on my Vercel deployment and the difference in the session load speed is immense. Much better! Thanks

This issue is particularly noticeable when Vercel’s platform experiences additional latency - API calls to a protected endpoint simply start timing out.

Anything we can do in userland to avoid the additional network request?

Just to add another success story to this thread. I just migrated a project from v3 to v4 (to address these performance issues), and updated my server route to use getServerSession over getSession. Prior to the update the just the session check was taking between 1s and 5s. After the update, the session check is taking between 1ms and 20ms, usually less than 2ms! This equates to a nearly 1000x increase in performance! Absolutely game-changing!

One note, not necessarily related to getServerSession is that I’m now consistently getting this error on every auth check, but it’s still working correctly so 🤷.

ERROR	[next-auth][error][MISSING_NEXTAUTH_API_ROUTE_ERROR] 
https://next-auth.js.org/errors#missing_nextauth_api_route_error Cannot find [...nextauth].{js,ts} in `/pages/api/auth`. Make sure the filename is written correctly. MissingAPIRoute [MissingAPIRouteError]: Cannot find [...nextauth].{js,ts} in `/pages/api/auth`. Make sure the filename is written correctly.
    at assertConfig (/var/task/node_modules/next-auth/core/lib/assert.js:19:12)
    at NextAuthHandler (/var/task/node_modules/next-auth/core/index.js:34:52)
    at getServerSession (/var/task/node_modules/next-auth/next/index.js:64:51)
    at contentfulAPI (/var/task/.next/server/pages/api/contentful.js:4578:91)
    at apiResolver (/var/task/node_modules/next/dist/next-server/server/api-utils.js:8:7)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    at async Server.handleApiRequest (/var/task/node_modules/next/dist/next-server/server/next-server.js:67:462)
    at async Object.fn (/var/task/node_modules/next/dist/next-server/server/next-server.js:59:492)
    at async Router.execute (/var/task/node_modules/next/dist/next-server/server/router.js:25:67)
    at async Server.run (/var/task/node_modules/next/dist/next-server/server/next-server.js:69:1042) {
  code: 'MISSING_NEXTAUTH_API_ROUTE_ERROR'
}

@davudk What version of next-auth are you using? I had a very similar behavior when I was using next-auth@4.0.0-beta.7, when I upgraded to next-auth@0.0.0-pr.3222.41318883 these went away.

To add a data point here: https://github.com/prisma/prisma/issues/7009#issuecomment-838915024 This is a Prisma user who attributed the latency in his app to Prisma in the beginning. We then, with the help of @kripod, figured out that this might indeed be a Vercel deployment + Nextauth issue as described above.

Fixing this in some way or protecting users in serverless environments would be very nice. (And yep, we know the pain of serverless deployments at Prisma as well. We are trying everything to make it nice for people, but some problems are just still unsolved. [which is totally not Vercel’s fault by the way, they are doing an amazing job of making serverless usable in the first place - but now people use it 😆])

This will also be the solution for #2850. That discussion made me aware that we have never actually updated the session cookie when getSession was called only server-side!