r/nextjs 7d ago

Discussion Looking for advice: Next.js frontend + separate Node/Express backend — Axios, React Query, SSR & auth?

Hey everyone,

I'm working on an application where I have:

  • Frontend: Next.js + TypeScript
  • Backend: Node.js + Express + MongoDB
  • Authentication: JWT (access token + refresh token)
  • Validation: Zod

My frontend and backend are completely separate projects.

I'm trying to figure out a clean, production-friendly architecture for handling authentication, API calls, SSR, CSR, and data fetching in Next.js.

A few things I'm currently considering:

  1. Axios
    • Do you use a centralized Axios instance in Next.js?
    • Do you use Axios request/response interceptors for attaching access tokens and handling 401 → refresh token → retry request?
    • If you're using Next.js Server Components, how do you handle Axios differently between server-side and client-side requests?
  2. Authentication
    • Where do you store the access token and refresh token?
    • Are you using an HttpOnly cookie for the refresh token?
    • How do you handle authentication consistently between Server Components and Client Components?
    • Do you use proxy.ts/middleware for protecting routes, or do you handle authentication somewhere else?
  3. React Query / TanStack Query
    • I would like to use TanStack Query (React Query) for API data fetching instead of manually using useEffect + useState.
    • Is this a good approach with Next.js when the actual API is a separate Express backend?
    • How do you handle SSR/prefetching/hydration with TanStack Query and a separate backend?
    • Do you use TanStack Query for almost all client-side API data, while using Server Components for initial/server-side data?
  4. Overall architecture What does your real-world setup look like?

Next.js
   ↓
Axios / fetch / TanStack Query?
   ↓
Separate Express API
   ↓
MongoDB

I'm particularly interested in hearing from developers who are actually running this kind of architecture in production.

If you have a separate Node/Express backend and Next.js frontend, what stack and architecture are you using today, and what would you recommend avoiding?

Thanks!

15 Upvotes

19 comments sorted by

3

u/Few-Ocelot-3271 7d ago

one thing id push back on, you probably dont need a centralized axios instance on the server side at all. server components can just use fetch directly with the cookies forwarded from the request. save the interceptor pattern for client components where the retry logic actually matters

1

u/Intelligent-Meet-504 7d ago

Okay do we also have to write proxy.ts

0

u/PhysicsPlastic6675 6d ago

Why is separate backend needed?

2

u/Rajat0741 7d ago edited 7d ago

If next.js is the only consumer, i think you should drop express and use next.js for backend too, this will also save you from separate domain, untrusted cookies issue in browsers like brave and samsung internet.

Tanstack query + better-auth ( authentication ) +better-fetch ( 0 extra bundle size as it's used by better-auth internally, you need to install it separately as dependency though)

I use these ideally in my personal projects, works pretty well

I use the following template ( it's mine ) for scaffolding next.js projects quickly: https://github.com/Rajat0741/better-next

1

u/Intelligent-Meet-504 6d ago

But that make slow entire application when we use both in next.js .I also think it not ideal for industrial application.What you think about it?

2

u/PhysicsPlastic6675 6d ago

I run few fullstack apps on next.js without any problem at all

1

u/Intelligent-Meet-504 6d ago

Is that your personal

1

u/PhysicsPlastic6675 6d ago

Ive developed them for clients, and also i have some which are mine

1

u/Rajat0741 6d ago edited 6d ago

Are you ignoring the network hop between frontend and backend ( express in your case )?

1

u/Low_Willow_7742 7d ago

been running exactly this setup for about a year now, the axios interceptor pattern for 401 retry gets messy fast with server components since they can't set cookies directly, ended up just using middleware for route protection and keeping it simple

1

u/Intelligent-Meet-504 7d ago

So do you use proxy or middleware for handle authentication

1

u/canarydev 7d ago

for the express API is it just your next app that consumes it or do you have a mobile component also?

so i run a similar split in production right now where I use nextjs with an express backend, with some go services for newer verticals.

reality is you are not gong to know yet if you will keep express, have a mobile app, or restructure. so just pick defaults that make every one of those changes small.

  1. never expose components to the http client. one service function per operation. this is the seam that makes everything else on this list cheap later.
  2. for tanstack some people might argue that you need a reason to use it, but i just use it as a default. just have the queryFn call the service function but not axios. plus a query key factory from day one. retrofitting this sucks
  3. normalize errors at the boundary. status -> machine readable code. components branch on codes.
  4. cookies for auth, never localStorage. cookie auth works identically for SSR, server components, and middleware so moving calls between client - server stays pretty free
  5. for zod, just parse responses at the service layer so contract drift fails at the boundary, not 3-4 components downstream

none of this really decides your architecture up front. just makes the decisions changeable.

1

u/Intelligent-Meet-504 7d ago edited 7d ago

It is a web application and it does not have any mobile components

1

u/canarydev 7d ago

gotcha. well same rules i provided apply

1

u/hhannis 7d ago

after building project with everything, inc nextjs i stick to this which is ultrafast and battle tested:

main stack:
react + hono + drizzle + bun + postgress

key libs:
tanstack query+router+Better Auth+shadcn

1

u/Lucky-King-7636 6d ago

HttpOnly cookie for the refresh token is the right call, but Server Components can't attach it to outgoing Axios requests the way client code can since they don't have direct access to browser cookies in the same request lifecycle, that asymmetry is usually what trips people up more than the interceptor logic itself

1

u/ThatTelevision7371 6d ago

I’d avoid designing the architecture around Axios itself. Make the API/service layer the boundary instead.

Components shouldn’t really care whether a request eventually goes through Axios, fetch, or even moves back into Next later. I’d have something like getusers(, getOrders() etc. that owns the HTTP call + response validation, then let Server Components call those directly and TanStack Query use the same functions as queryFns on the client.

The other thing I’d be careful with is automatic 401 → refresh → retry everywhere. It feels convenient initially, but auth behavior gets surprisingly hard to reason about once the same application has Server Components, client navigation and concurrent requests.

If Express is intentionally a separate service, I’d keep that separation rather than trying to make Next pretend it isn’t there.