Routing is where many Vue applications earn their behavior, and Vue Router offers layered hooks for controlling navigation. router.beforeResolve is a global guard that runs after in-component navigation guards and async route components have resolved but before navigation is confirmed, which makes it a strong place for final checks such as permission or data readiness. router.afterEach fires only after a navigation has successfully completed and cannot change its outcome; it is most often used for analytics, logging, or page-level cleanup. Navigation guards in general are useful whenever you need to block, redirect, or prepare for a route change, whether for auth, unsaved data, permissions, or preloading data.
Performance and clarity both improve when you treat route shapes intentionally. Lazy loading a route means the component is imported only when that route is activated, shrinking the initial bundle and speeding up first load. It also helps to distinguish route params from query params: route params are part of the URL path and typically identify a resource (such as /users/:id), while query params modify how that resource is presented (such as /users?sort=asc&page=2). Encoding the relationship this way makes URLs shareable, bookmarkable, and predictable.
For shared application state, Pinia is the recommended store. A Pinia store is a centralized reactive module composed of state, actions, and derived values, with structure, tooling, traceability, and cleaner testing than ad-hoc global objects offer. For smaller, scoped sharing, Vue's built-in provide and inject let values flow through the component tree without prop drilling, though the tradeoff is that data flow becomes less explicit when used too liberally. For faster first paint and better crawlability, static site generation (SSG) pre-renders pages to HTML at build time. The server-side counterpart is server-side rendering, where the matching client concern is hydration: Vue attaches reactivity and event listeners to the server-rendered HTML on the client. Hydration mismatch errors happen when the server and client output diverge, typically because of random values, time-based content, or browser-only state being rendered into the initial tree.