Most caching surprises in the App Router trace back to a single question the framework asks about every route: can this page be rendered before a request arrives? If it can, it is rendered once and reused. If it cannot, it is rendered per request.
Static until proven dynamic
A route starts out eligible for static rendering. It stays that way until the code reads something that only exists at request time: cookies, request headers, or the search parameters of the URL. The moment a component reads one of those, the route has to wait for a request.
That is why a page can flip from fast to slow after an innocent change. Nobody asked for dynamic rendering; a helper deep in the tree read a cookie.
Data has its own clock
Rendering and data are cached separately. A static page can still hold data that expires, and a dynamic page can still reuse cached data. Time-based revalidation says how old data may get. Tag-based revalidation lets a write mark exactly the data it affected as stale.