You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
server-only Module Causes Build Failure in Development Mode (Inconsistent Behavior Between Development and Production Builds) #1967
The project encounters a build failure in development mode when attempting to import the server-only module from a file meant to handle server-side logic. This issue does not occur in the production build, leading to inconsistent behavior between development and production environments.
Your Example Website or App
N/A
Steps to Reproduce the Bug or Issue
In start-basic-rsc sample.
In app/utils/posts.tsx put the following
// import { notFound } from '@tanstack/react-router'// import { createServerFn } from '@tanstack/start'importaxiosfrom'redaxios'import{getPost}from'./static-post'import{createServerFn}from'@tanstack/start'exporttypePostType={id: stringtitle: stringbody: string}exportconstfetchPost=async(postId: string)=>{'use server'console.info(`Fetching post with id ${postId}...`)awaitnewPromise((r)=>setTimeout(r,500))constpost=awaitaxios.get<PostType>(`https://jsonplaceholder.typicode.com/posts/${postId}`).then((r)=>r.data).catch((err)=>{if(err.status===404){// throw notFound()}throwerr})returnpost}exportconstfetchPosts=async()=>{'use server'console.info('Fetching posts...')awaitnewPromise((r)=>setTimeout(r,500))returngetServerPost()}exportconstgetServerPost=createServerFn('GET',()=>{returngetPost()})
Then add a new file static-post.ts in the same folder with the following contents.
import'server-only'exportfunctiongetPost(){return[{userId: 1,id: 1,title:
'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',body: 'quia et suscipit suscipit recusandae consequuntur expedita et cum reprehenderit molestiae ut ut quas totam nostrum rerum est autem sunt rem eveniet architecto',},]}
If you try to build the project and start it. It will work fine and will not include the server only files, but in dev it will fail
2:43:47 [vite] Error when evaluating SSR module /app/utils/posts.tsx: failed to import "server-only"
|- Error: This module cannot be imported from a Client Component module. It should only be used from a Server Component.
Expected behavior
The project should build and start successfully in both development and production modes without encountering import errors.
More of a question, but would also be curious to know if this is the intended way to exclude certain files from client bundle / whether tanstack start intends to have any pragmas for excluding server side only code.
Reacted by Nace Logar, Doniel Moins, Wenqi Huang and Katsuma Ito
If you're using tanstack start, I found an interesting "solution " to this problem.
I'm not sure if it will compile everything to the browser version as well, but for me, it saved me from having to ship @prisma/client to my browser bundle. So I recommend you try it out with that get-posts function, then do a quick ctrl + f in your browser bundle.
all it does now is throw an error in the console that a server function should only be called from the server.
Also, the only reason I am proposing this as a "solution" is due to the fact that there is no documented built-in which does something similar. This is very much putting a "band aid" on the problem.
Please do NOT ship something like this into prod.
If there is an actual supported solution somewhere out there, it would really be appreciated
I am using redis, but it seems the problem is the same, I've done the following and it seems it does not produce server only errors or attempts to include redis bundle into the client. The key part is dynamically importing the client (could probably work for prisma client as well)
importtype{createClientas_createClient}from"redis";import{createMiddleware}from"@tanstack/react-start";letredis: ReturnType<typeof_createClient>|null=null;functioncreateRedisServerMiddleware(){returncreateMiddleware({type: "function",validateClient: false,}).server(async({ next })=>{if(!redis){const{ createClient }=awaitimport("redis");redis??=createClient({url: `redis://${process.env.REDIS_ENDPOINT}`,});}// eslint-disable-next-line no-consoleredis.on("error",(err)=>console.log("Redis Client Error",err));if(!redis.isReady){awaitredis.connect().catch((err)=>{// eslint-disable-next-line no-consoleconsole.error("Failed to connect to Redis:",err);});}constresult=awaitnext({context: { redis }});redis.close();returnresult;});}export{createRedisServerMiddleware};
I get an error because I use the postgres library. Through the imports (db -> server function -> client side) it tries to execute postgres on the client side and that gives me the error - Buffer is not defined
This is now covered by Start’s import-protection system. Modules that access server-only code only inside createServerFn or other server compiler boundaries are supported in build and dev mode.
If you can reproduce a current-version failure with a minimal example, please open a new issue and include the import chain and Start version :)
Activity
uap-dev commentedon Mar 8, 2025
More of a question, but would also be curious to know if this is the intended way to exclude certain files from client bundle / whether tanstack start intends to have any pragmas for excluding server side only code.
DonielMoins commentedon Apr 18, 2025
If you're using tanstack start, I found an interesting "solution " to this problem.
I'm not sure if it will compile everything to the browser version as well, but for me, it saved me from having to ship
@prisma/clientto my browser bundle. So I recommend you try it out with that get-posts function, then do a quickctrl + fin your browser bundle.here is a short snippit of what I did
all it does now is throw an error in the console that a server function should only be called from the server.
Also, the only reason I am proposing this as a "solution" is due to the fact that there is no documented built-in which does something similar. This is very much putting a "band aid" on the problem.
Please do NOT ship something like this into prod.
If there is an actual supported solution somewhere out there, it would really be appreciated
Nedi11 commentedon Jul 10, 2025
Any update
LiniovasDovydas commentedon Jul 12, 2025
I am using redis, but it seems the problem is the same, I've done the following and it seems it does not produce server only errors or attempts to include redis bundle into the client. The key part is dynamically importing the client (could probably work for prisma client as well)
max-programming commentedon Jul 24, 2025
I get an error because I use the
postgreslibrary. Through the imports (db -> server function -> client side) it tries to executepostgreson the client side and that gives me the error -Buffer is not definedThis is how I solved my issue: #3401 (comment)
Ynng commentedon Aug 19, 2025
getting the same
Buffer is not definederror with postgres and drizzle.ended up adopting DonielMoins's hack #1967 (comment)
LadyBluenotes commentedon Jul 11, 2026
This is now covered by Start’s import-protection system. Modules that access server-only code only inside
createServerFnor other server compiler boundaries are supported in build and dev mode.If you can reproduce a current-version failure with a minimal example, please open a new issue and include the import chain and Start version :)