Ask
118
@duckweed_dev ·

the edge runtime does not support Node.js crypto module, only in middleware Edge Runtime

Build fails with:

Error: The edge runtime does not support Node.js 'crypto' module.
  Learn more: https://nextjs.org/docs/messages/node-module-in-edge-runtime

It only happens for middleware.ts. The same import in a route handler is fine. All middleware does is read a session cookie and redirect to /login when it is missing - it does not knowingly touch crypto at all. The import chain goes middleware -> @/lib/auth -> a session helper -> jsonwebtoken.

Next 15.3. Do I need to give up on checking the session in middleware, or is there a shape that works?

9 answers Share
Report

Answering anonymously — a moderator will review it first.

  • @cast_iron_carl · 2d ago · 3 replies

    Swap jsonwebtoken for jose and the error goes away. jose is built on Web Crypto, which the edge runtime does have, and verify looks like this:

    import { jwtVerify } from 'jose'
    const secret = new TextEncoder().encode(process.env.JWT_SECRET)
    const { payload } = await jwtVerify(token, secret)
    

    The deeper fix is the import chain. @/lib/auth almost certainly also pulls in your database client and a password hashing library, and middleware runs on every matched request including static assets if your matcher is sloppy. Make a separate lib/auth-edge.ts that contains only cookie reading and token verification, import that from middleware, and keep the fat one for route handlers.

    84
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
    • @cast_iron_carl · 2d ago

      Make the edge one the primitive and have the Node one import it. auth-edge.ts exports readSessionToken(cookies) and verify(token); auth.ts imports both and adds the database lookup on top. One implementation, two entry points, and the fat one can never accidentally leak into the thin one because the dependency only points one way.

      47
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
    • @duckweed_dev · 16h ago

      The split file worked. Slightly worried about having two places that know how to read a session - is there a way to keep them from drifting apart?

      33
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
  • @crimp_not_solder · 14h ago

    Recent Next versions have experimental support for running middleware on the Node runtime, which would make the error go away without changing your imports. I would still not reach for it here - opting middleware into Node means your redirect for anonymous users now pays a Node cold start on the path of every request, which is a worse trade than replacing one JWT library.

    38
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @two_vcpu_club · 3h ago · 2 replies

    Also worth stating plainly: middleware should not be your authorisation. Verifying a signature there is fine as a cheap redirect for logged-out users, but the actual check belongs where the data is read, in the route handler or the server component. If somebody ever hits your API directly, middleware is not what saves you. Treat it as UX, not as a gate, and the pressure to cram a database call in there disappears.

    62
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
    • @printbed_gremlin · yesterday

      Worth saying louder. I have reviewed three codebases this year where the only role check lived in middleware and a matcher typo meant an entire admin section was open to anyone who knew the URL.

      29
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
  • @printbed_gremlin · yesterday

    If you use Auth.js, this is exactly what the split config exists for: an auth.config.ts with providers and callbacks but no adapter, imported by middleware, and the full auth.ts with the database adapter imported everywhere else. The adapter is what drags a Node-only driver into the edge bundle. Took me an embarrassingly long time to notice the docs had already solved my problem.

    47
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @listening_lane · 6h ago

    Check your matcher while you are in there. The default example matches everything except a few static paths, and people paste it and then add a database call. Narrow it to the routes that genuinely need the redirect and the whole class of problem gets smaller.

    26
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @pivot_pilot · 15h ago

    "It does not knowingly touch crypto" is doing a lot of work in a sentence that ends with jsonwebtoken.

    14
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report