Tag: Next.js

  • Caching in the Next.js App Router: Which Layer Is Answering?

    Caching in the Next.js App Router: Which Layer Is Answering?

    “I changed the API URL and the site still shows the old posts.” If you have built a Next.js site on top of a headless CMS, you have probably said something like this. The App Router caches aggressively and in several layers, and most confusing bugs come from not knowing which layer is answering. This is the mental model I use.

    Layer 1: environment variables are read at start or build time

    Values in .env.local are loaded when the dev server starts or when you build. Editing the file while the server runs changes nothing until you restart. Also check which folder the server runs from: each project folder (and each git worktree) reads its own env file.

    Anything prefixed NEXT_PUBLIC_ is inlined into the browser bundle at build time, so it is both public and frozen. Secrets such as API tokens must never use that prefix.

    Layer 2: pages rendered at build time

    Routes that can be pre-rendered are generated during next build. With generateStaticParams, every slug you return becomes static HTML. That makes pages instant, but it also means:

    • The CMS must be reachable from the build machine.
    • Content changes only appear after revalidation or a rebuild.
    • Config read at build time, such as allowed image hosts in next.config.js, needs a rebuild to change.

    Layer 3: the data cache

    For data that does not come from a plain fetch, such as an axios client or an SDK, unstable_cache wraps a function and stores its result on the server:

    import { unstable_cache } from "next/cache";
    
    export const getPosts = unstable_cache(
      async () => fetchPostsFromCms(),
      ["cms-posts", API_BASE, String(CATEGORY_ID)],
      { revalidate: 120 }
    );

    Two parts deserve attention:

    • Key parts. The array is part of the cache key. Include everything that changes the result, such as the API base URL and category ID. If you leave the URL out, switching environments can keep serving the old environment’s data.
    • Revalidate. After the window expires, the next request still gets the cached value while a fresh one is fetched in the background. If that fetch fails, the stale value keeps being served, which is usually what you want for a blog, but can look like “nothing changed”.

    Newer Next.js versions also offer the "use cache" directive with cache life profiles. The concepts are the same: a key, a lifetime and a way to invalidate.

    Layer 4: on-demand invalidation

    Time-based revalidation is a safety net, not a publishing workflow. For instant updates, tag cached data and invalidate the tag when the CMS changes:

    // app/api/revalidate/route.ts
    import { revalidateTag } from "next/cache";
    
    export async function POST(request: Request) {
      const secret = request.headers.get("x-revalidate-secret");
      if (secret !== process.env.REVALIDATE_SECRET) {
        return new Response("Unauthorized", { status: 401 });
      }
      revalidateTag("cms-posts");
      return Response.json({ revalidated: true });
    }

    Point a CMS webhook (for WordPress, a small plugin or a save_post hook) at this route, and published posts show up within seconds without waiting for the timer.

    Layer 5: the browser and the router

    The client-side router keeps recently visited segments in memory, so pressing back can show what you saw a minute ago. A hard refresh rules this layer out quickly when debugging.

    A debugging checklist

    1. Restart the dev server and confirm it runs from the folder whose env file you edited.
    2. Check that the variable is read server-side and not inlined with NEXT_PUBLIC_.
    3. Confirm the cache key includes the values you changed.
    4. Look at the server logs for failed revalidation fetches.
    5. For production, ask whether the page was built statically and needs revalidation or a rebuild.

    Caching is what makes a headless setup feel fast. Knowing which layer is answering is what makes it feel predictable.

  • Lovers Finder

    Lovers Finder

    Lovers Finder is a modern dating platform built as a Telegram Mini App, designed to make meeting new people easier, more accessible and more enjoyable. It is an independently developed product: I designed and built it myself as the first step toward running my own business.

    The idea

    The goal is to help people discover meaningful connections through a seamless, intuitive experience, without installing a separate application. Everything runs inside Telegram, where the users already are.

    Key features

    • Smart profile discovery and matching.
    • Personalised user profiles with photo uploads.
    • Real-time messaging between matched users.
    • User verification and profile trust features.
    • VIP membership and premium features.
    • Seamless integration with the Telegram ecosystem.
    • A modern, responsive UI focused on user experience.

    How it is built

    The product is built with a focus on scalability, performance and user experience:

    • Next.js and React for the Mini App interface
    • Node.js and Express for the API
    • MongoDB for data
    • Cloudflare R2 for photo storage
    • Telegram Mini Apps API for the integration with Telegram

    Finding your partner is on us, the first date is on you.

    Explore Lovers Finder on Telegram.

  • Nexu.co

    Nexu.co

    Nexu is a startup platform where users book online consultations with specialists in psychology, medicine and nutrition. I worked on it as a front-end developer for over two years, building the web app that patients use to find a specialist, book a session and manage their care.

    The product

    The web app brings three kinds of consultation into one place. Users browse specialists, compare their profiles, pick a time and attend their sessions online. Everything has to feel calm and trustworthy, because people often arrive at a stressful moment.

    My role

    • Built the user-facing web app with React and Next.js, using TypeScript throughout.
    • Connected the interface to the platform’s REST APIs for specialists, bookings and user accounts.
    • Developed responsive interfaces that work as well on phones as on desktop.
    • Implemented the app as a fast single-page experience to improve performance and usability.

    Tech stack

    • React and Next.js
    • TypeScript
    • Web APIs and REST APIs

    Visit the product at nexu.co.

  • Nexu Dashboard Panel

    Nexu Dashboard Panel

    The Nexu Dashboard Panel is the HR dashboard for Nexu’s partner companies. It lets each company manage its users, their access to consultations and the other settings that come with offering Nexu as an employee benefit. I was the front-end developer on the panel.

    The problem

    Partner companies needed one place to onboard employees, manage their accounts and keep track of how the service was being used, without contacting Nexu support for every change.

    My role

    • Built the full HR dashboard with React, Next.js and TypeScript.
    • Created interactive dashboards with real-time data visualisation.
    • Used MUI for a consistent, accessible component base, and Redux for shared application state.
    • Contributed to a custom UI library that increased developer productivity and code reuse across Nexu projects.
    • Integrated the panel with the platform’s REST APIs.

    Tech stack

    • React, Next.js and TypeScript
    • MUI
    • Redux
    • Web APIs and REST APIs