next.js: [Next13 App dir] Bug with server-only being used in an API route handler

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 22.0.0: Mon Aug  1 06:32:20 PDT 2022; root:xnu-8792.0.207.0.6~26/RELEASE_ARM64_T6000
Binaries:
  Node: 16.15.0
  npm: 8.5.5
  Yarn: N/A
  pnpm: N/A
Relevant packages:
  next: 13.0.6
  eslint-config-next: 13.0.6
  react: 18.2.0
  react-dom: 18.2.0

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true)

Link to reproduction - Issues with a link to complete (but minimal) reproduction code will be addressed faster

https://github.com/KolbySisk/next-server-only-bug

To Reproduce

  1. Create a client component that makes a request to an api route (A form that posts data to an api route, for example) 2.npm i server-only
  2. Add import "server-only"; to the api route.
  3. Run and make the request to the api route.

See error:

You're importing a component that needs server-only. That only works in a Server Component but one of its parents is marked with "use client", so it's a Client Component.

Describe the Bug

API routes are handled only on the server, so I would expect import "server-only"; to work fine.

More realistically, I have a function which includes sensitive information that I want to ensure only runs on the server. It can be used in both a server component, and an API route, given the context.

I’m also curious how Next even knows about the relationship between a client component and an API route handler.

Expected Behavior

Code is executed as expected without the error.

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

NEXT-1385

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 25
  • Comments: 29 (10 by maintainers)

Commits related to this issue

Most upvoted comments

Same thing on my end. I am using server-side logic code in a Server component with server-only, and it is working properly. However, now I need to use the same logic in my API and my build is failing.

I think there is still an issue with API routes wrongly being confused with client components. I have a function that uses:

import { cookies } from "next/headers";

and is used in an API route. The function should only be run by server-side code so this is ok, but NextJS thinks that the calling functions (API routes) are client-side:

./lib/getUser.js

You're importing a component that needs next/headers. That only works in a Server Component but one of its parents is marked with "use client", so it's a Client Component.

   ,----
 7 | import { cookies } from "next/headers";
   : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   `----

One of these is marked as a client entry with "use client":
  lib/getUser.js
  pages/api/stripe/create-account.js

I can fix by adding import “server-only” to the api files but then I get the same error as @KolbySisk.

@ayhanap You can only import { cookies } from 'next/headers'; inside of server components not anywhere else. In middleware or api handlers, you should use the request object.

Same thing here.

When I run fetch within a “use client” (signup in this instance) page and use this server-side only import on the API’s side:

// pages/api/auth/signup.ts
import { createServerClient } from "@utils/supabase-server";

It returns:

You're importing a component that needs next/headers. That only works in a Server Component but one of its parents is marked with "use client", so it's a Client Component.
   ,----
 1 | import { headers, cookies } from "next/headers";
   : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   `----

One of these is marked as a client entry with "use client":
  src/utils/supabase-server.ts
  src/pages/api/auth/signup.ts

Even though I did not nest my API route within the “use client” page, it still thinks I did. My guess is that NextJS has some issues with combining API routes and the new App directory.

I get the same error whenever I import import { cookies } from 'next/headers'; in middleware.ts. Or any other file imports ‘next/headers’.

I am getting the same error as OP in a more complicated context but same issue of a call to API route handler from Client Component. I am using Next.js 13.2.4

Context: I am using useSWR(key, fetcher) with some data as an argument in a Client Component. The fetcher/helper function is marked server only as it is using getServerSession (from next-auth) to get current user which is then used to get an active API key from a database using PrismaClient. API key is then used to do an authorised fetch with the data to a local API endpoint.

If I don’t mark this fetcher/helper server only, then my db lookup throws an error as PrismaClient can not run in the browser.

What is the suggested method to make a call with user-inputted data from a Client component to an API route handler in Next.JS 13?

Hello every one, I found a solution provided by someone else: this.

This bug is very inexplicable. I have been developing the project for a while, but today it suddenly fails to compile! sad…

Just throwing my name here for a 👍 for this issue, as I just hit it.

I use import “server-only” in my backend authentication code to make sure no one imports it in a client component tree. But I need to use the same code in server components as I do in APIs. Unfortunately, server-only fails in API routes, so I can’t. I have to move it up to a wrapper or something made just for server components, but then my auth code is vulnerable to someone making an honest mistake.

It would be great if I could use server-only to poison my code against client side usage but still have it work with route handlers.

@timneutkens I’m still getting You're importing a component that needs next/headers. That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/react-essentials#server-components in next version 13.4.10

@OliverRC that sitemap issue has been fixed in 13.4.10 👍

This is also happening if your server component and client component exported at same level/place:

Structure:

\mixed_component
    \server_component_contains_next_headers
    \client_component_marked_use_client
    index.ts

index.ts:

export * from "./server_component"; // contains import { cookies } from 'next/headers'; 
export * from "./client_component_marked_use_client";

If you import mixed_component somewhere, you will get the error:

You're importing a component that needs next/headers. That only works in a Server Component but one of its parents is marked with "use client", so it's a Client Component.

One of these is marked as a client entry with "use client":
./mixed_component/index.ts

@logemann

You can only import { cookies } from ‘next/headers’; inside of server components and not anywhere else. In api handlers, you should use the req object with req.headers (I think) and req.cookies.

I think it is rightfully a bug, with NextJs confusing the api route as a client component, but I also think that these directives should fail, as you imported cookies which is a function you can only use in server components but not anywhere else, you’d have to use the request object in your api handler.

same thing for server-only which is supposed to be a guardrail when you import them from a react component (wether it is client or server one).

When you try to use them in a different context out of react (i.e api handlers) NextJs is lost and produces and generic incorrect error