I Broke My React Query Cache by Using <a> tag in Next.js — Here's What I Learned

· 2 min read · Originally on Medium

I Broke My React Query Cache by Using <a> tag in Next.js — Here's What I Learned

Intro

While working on a full-stack app using Next.js App Router, shadcn UI, React Query, and NextAuth, I ran into an unexpected bug: navigating between internal pages would reset my entire app state.

At first glance, everything seemed fine — the routes loaded, styles applied correctly, and the layout didn't break. But then I realized that:

  • React Query lost its cache
  • NextAuth session flickered
  • The whole React tree was unmounted and remounted

Turns out, I was using a native <a> tag to navigate between pages. Here's why that caused issues — and how switching to Next.js-native routing fixed everything.

The Problem

I used this:

<a href="/garage">Go to Garage</a>

It worked visually, but each time I clicked the link, the entire app reloaded. This triggered a complete teardown and reinitialization of:

  • React Query Provider
  • NextAuth session
  • Global context state

What seemed like a harmless anchor tag ended up resetting my app on every navigation.

Why It Happened

The root issue is how different navigation methods are handled by the browser and by Next.js.

TL;DR:

  • <a> tag → full page reload → app resets
  • next/link or router.push() → client-side navigation → app state preserved

How I Fixed It

Replaced <a> with next/link

import Link from 'next/link';
 
<Link href="/garage">Go to Garage</Link>

This allows Next.js to handle routing internally without reloading the page, keeping React Query and NextAuth state intact.

Used router.push() for programmatic navigation

When I needed to navigate after a form submit or a conditional redirect:

'use client';
import { useRouter } from 'next/navigation';
 
const router = useRouter();
router.push('/garage');

Conclusion

If you're building with React Query, NextAuth, or any stateful client libraries, never use <a> for internal navigation. It'll silently break your cache and context, and you might not notice until debugging hours later.

Instead:

  • Use next/link for declarative navigation inside components
  • Use router.push() for programmatic routing
  • Only use <a> for external URLs or non-JS fallbacks

A simple change saved me hours of debugging — hopefully, it saves you too.

Keep reading

Mastering Image Optimization in Next.js

Learn how to fix memory issues caused by Next.js image optimization and scale your app using CDNs, srcSet, and smart caching strategies.

I Accidentally Built a Software Factory

While building Forge, I wrote a skill file so agents could fix issues overnight. A few weeks later, everyone was talking about software factories, a term from 1968.

View all blogs

About the author

Thant Hein Thwin

Lead Software Engineer

Available for work