Are GET route handlers (route.tsx) prefetched by Link in production?
Unanswered
Masai Lion posted this in #help-forum
Masai LionOP
I woke up to a subtle bug today caused by a <Link> prefetching a GET route.tsx handler.
The handler logic delete some cookies and it's meant to be intentionally triggered by the user. I had the route in a <Link> href prop without the prefetch option specified.
The documentation for <Link> says:
Prefetch behavior depends on whether the route is static or dynamic. For static routes, the full route will be prefetched (including all its data). For dynamic routes, the partial route down to the nearest segment with a loading.js boundary will be prefetched.
I thought my route was dynamic because it manipulates cookies and therefore can’t be static. So my question is: what was wrong in my reasoning? Is this a bug in the prefetch behavior? Should I always treat GET route handlers as "static" an therefore prefetched?
Thanks
The handler logic delete some cookies and it's meant to be intentionally triggered by the user. I had the route in a <Link> href prop without the prefetch option specified.
The documentation for <Link> says:
Prefetch behavior depends on whether the route is static or dynamic. For static routes, the full route will be prefetched (including all its data). For dynamic routes, the partial route down to the nearest segment with a loading.js boundary will be prefetched.
I thought my route was dynamic because it manipulates cookies and therefore can’t be static. So my question is: what was wrong in my reasoning? Is this a bug in the prefetch behavior? Should I always treat GET route handlers as "static" an therefore prefetched?
Thanks
8 Replies
@Masai Lion I woke up to a subtle bug today caused by a <Link> prefetching a GET route.tsx handler.
The handler logic delete some cookies and it's meant to be intentionally triggered by the user. I had the route in a <Link> href prop without the prefetch option specified.
The documentation for <Link> says:
Prefetch behavior depends on whether the route is static or dynamic. For static routes, the full route will be prefetched (including all its data). For dynamic routes, the partial route down to the nearest segment with a loading.js boundary will be prefetched.
I thought my route was dynamic because it manipulates cookies and therefore can’t be static. So my question is: what was wrong in my reasoning? Is this a bug in the prefetch behavior? Should I always treat GET route handlers as "static" an therefore prefetched?
Thanks
you should never use a GET route to mutate data. use a different http verb and a
<button>
instead of <a>
/<Link>
Original message was deleted
hi there, we do not permit AI-generated answers in this server
@joulev you should never use a GET route to mutate data. use a different http verb and a `<button>` instead of `<a>`/`<Link>`
Masai LionOP
Ok good not know but even next-intl does set a cookie by simply navigating to a certain link.
Is this a next.js specifc thing? Cause i've always seen Set-Cookie headers in GET reqs
Also this don't answer my question. Why is that route prefetch'd? Is it considered static by default because is a GET?
Is this a next.js specifc thing? Cause i've always seen Set-Cookie headers in GET reqs
Also this don't answer my question. Why is that route prefetch'd? Is it considered static by default because is a GET?
The problem is already fixed, i don't need a solution. I need an explanation
@Masai Lion Ok good not know but even next-intl does set a cookie by simply navigating to a certain link.
Is this a next.js specifc thing? Cause i've always seen Set-Cookie headers in GET reqs
Also this don't answer my question. Why is that route prefetch'd? Is it considered static by default because is a GET?
no i'm simply giving feedback that it is not a great idea to perform mutations in GET routes. logging in/out is a mutation, that's why you don't see
/api/auth/login
for example being GET.Also this don't answer my question. Why is that route prefetch'd? Is it considered static by default because is a GET?now this one i don't know for sure. it should not be prefetched, but it is – this is likely a bug. perhaps
<Link>
only recognises other pages for static/dynamic handling and didn't expect to be provided a route handler to its href
. will need to dive into the source code to figure that out though.@joulev no i'm simply giving feedback that it is not a great idea to perform mutations in GET routes. logging in/out is a mutation, that's why you don't see `/api/auth/login` for example being GET.
> Also this don't answer my question. Why is that route prefetch'd? Is it considered static by default because is a GET?
now this one i don't know for sure. it _should_ not be prefetched, but it is – this is likely a bug. perhaps `<Link>` only recognises other pages for static/dynamic handling and didn't expect to be provided a route handler to its `href`. will need to dive into the source code to figure that out though.
Masai LionOP
Your feedback is welcome, didn't mean to sound harsh. I know that mutations that changes server side state should not be performed in get handlers, but my case was more like a "preference" cookie. Pretty much like the NEXT_LOCALE language preference of next-intl
Your second point is very helpful, i didn't know that Link was made exclusively for pages routes
Your second point is very helpful, i didn't know that Link was made exclusively for pages routes
@Masai Lion Your feedback is welcome, didn't mean to sound harsh. I know that mutations that changes server side state should not be performed in get handlers, but my case was more like a "preference" cookie. Pretty much like the NEXT_LOCALE language preference of next-intl
Your second point is very helpful, i didn't know that Link was made exclusively for pages routes
oh i see. still yeah i think in the nextjs ecosystem, for this you are expected to use a server action instead, with
cookies().delete()
inside it. y'know, nextjs doing nextjs things. i even think for most apps you don't even need route handlers anymore unless those route handlers are for use by an external application/serviceYour second point is very helpful, i didn't know that Link was made exclusively for pages routesthat was just speculation on my part, an educated guess based on past bugs that the framework has had. please don't take it as the truth, though i wouldn't be too surprised to find out it is the truth. that said it remains true that this is a bug indeed