The Crumb Trail: Managing Cookies in Next.js🍪
Aman Sahu

Aman Sahu @amankrsahu

Location:
New Delhi, India
Joined:
Mar 13, 2025

The Crumb Trail: Managing Cookies in Next.js🍪

Publish Date: Jun 26
7 0

Let me tell you a story about how I once spent an entire afternoon debugging why my user preferences weren't persisting, only to discover I'd set a cookie with path=/admin while my app was running at path=/. That was the day I vowed to master cookie management in Next.js, and today, I'm going to share that hard-earned knowledge with you.

🧐 Why Bother With Proper Cookie Management?

Cookies are like the breadcrumbs of the web (hence the terrible pun in this post's title). They help us remember user preferences, maintain sessions, and keep our applications stateful. But much like real breadcrumbs, if you don't manage them properly, you'll end up with a mess.

🛠️ The Building Blocks

Here are the two files you'll need to implement in your project:

lib/cookies.ts - The Core Utility

export type CookieOptions = {
  days?: number;
  path?: string;
  domain?: string;
  secure?: boolean;
  sameSite?: "Lax" | "Strict" | "None";
};

export class ClientCookies {
  /**
   * Set a cookie
   * @param name Cookie name
   * @param value Cookie value
   * @param options Cookie options
   */
  static set(name: string, value: string, options: CookieOptions = {}) {
    if (typeof window === "undefined") return;

    const {
      days = 30,
      path = "/",
      domain,
      secure = window.location.protocol === "https:",
      sameSite = "Lax",
    } = options;

    let cookieString = `${name}=${encodeURIComponent(value)}`;

    if (days) {
      const date = new Date();
      date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
      cookieString += `; expires=${date.toUTCString()}`;
    }

    cookieString += `; path=${path}`;
    if (domain) cookieString += `; domain=${domain}`;
    if (secure) cookieString += "; secure";
    if (sameSite) cookieString += `; sameSite=${sameSite}`;

    document.cookie = cookieString;
  }

  /**
   * Get a cookie value by name
   * @param name Cookie name
   * @returns Cookie value or null if not found
   */
  static get(name: string): string | null {
    if (typeof window === "undefined") return null;

    const cookies = document.cookie.split("; ");
    for (const cookie of cookies) {
      const [cookieName, cookieValue] = cookie.split("=");
      if (cookieName === name) {
        return decodeURIComponent(cookieValue);
      }
    }
    return null;
  }

  /**
   * Delete a cookie
   * @param name Cookie name
   * @param path Cookie path
   * @param domain Cookie domain
   */
  static delete(name: string, path = "/", domain?: string) {
    if (typeof window === "undefined") return;

    document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${path}${
      domain ? `; domain=${domain}` : ""
    }`;
  }

  /**
   * Check if a cookie exists
   * @param name Cookie name
   * @returns boolean indicating if cookie exists
   */
  static has(name: string): boolean {
    if (typeof window === "undefined") return false;
    return document.cookie
      .split("; ")
      .some(cookie => cookie.split("=")[0] === name);
  }
}
Enter fullscreen mode Exit fullscreen mode

Key Features:

  • 🔒 SSR-safe (won't break during server-side rendering)
  • 🛡️ Secure defaults (auto HTTPS detection)
  • 📦 Comprehensive cookie options
  • 🧹 Clean API for all cookie operations

hooks/use-cookies.ts - The React Hook

import { useEffect, useState } from "react";

import { ClientCookies, CookieOptions } from "@/lib/cookies";

type UseCookieReturn = {
  value: string | null;
  set: (value: string, options?: CookieOptions) => void;
  remove: () => void;
  has: boolean;
};

export const useCookie = (
  name: string,
  defaultValue?: string,
): UseCookieReturn => {
  const [cookieValue, setCookieValue] = useState<string | null>(() => {
    return ClientCookies.get(name) ?? defaultValue ?? null;
  });

  const set = (value: string, options?: CookieOptions) => {
    ClientCookies.set(name, value, options);
    setCookieValue(value);
  };

  const remove = () => {
    ClientCookies.delete(name);
    setCookieValue(null);
  };

  const has = ClientCookies.has(name);

  // Sync cookie changes between browser tabs
  useEffect(() => {
    const handler = () => {
      setCookieValue(ClientCookies.get(name) ?? defaultValue ?? null);
    };

    window.addEventListener("storage", handler);
    return () => window.removeEventListener("storage", handler);
  }, [name, defaultValue]);

  return { value: cookieValue, set, remove, has };
};
Enter fullscreen mode Exit fullscreen mode

Key Features:

  • ♻️ Reactive cookie values
  • 🔄 Automatic cross-tab synchronization
  • 🎣 Simple hook interface
  • ⚡ Optimized performance

🍪 Setting Cookies Like a Pro

Here's how to use our cookie system in your components:

// Using the ClientCookies directly
ClientCookies.set("user_token", "abc123", {
  days: 7,
  secure: true,
  sameSite: "Strict"
});

// Using the hook in a component
function UserPreferences() {
  const { value: theme, set: setTheme } = useCookie("theme", "light");

  const toggleTheme = () => {
    setTheme(theme === "light" ? "dark" : "light", { days: 30 });
  };

  return (
    <button onClick={toggleTheme}>
      Switch to {theme === "light" ? "dark 🌙" : "light ☀️"} mode
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

🔍 Cookie Inspection Made Easy

Check cookies with these simple methods:

// Check if cookie exists
if (ClientCookies.has("user_consent")) {
  loadAnalytics();
}

// Get cookie value
const userId = ClientCookies.get("user_id");

// With hook
const { value: userId, has: hasUserId } = useCookie("user_id");
Enter fullscreen mode Exit fullscreen mode

🗑️ Deleting Cookies Properly

Don't just forget about cookies - remove them correctly:

// Direct method
ClientCookies.delete("temp_session");

// Using hook
const { remove } = useCookie("auth_token");
remove();
Enter fullscreen mode Exit fullscreen mode

🌐 Real-World Use Cases

1. Authentication Flow 🔐

// After login
ClientCookies.set("auth_token", response.token, {
  days: 1,
  secure: true,
  sameSite: "Strict"
});

// In protected component
const { value: token } = useCookie("auth_token");

// On logout
const { remove } = useCookie("auth_token");
remove();
Enter fullscreen mode Exit fullscreen mode

2. User Preferences ⚙️

function FontSizeSelector() {
  const { value: fontSize, set: setFontSize } = useCookie("font_size", "16");

  return (
    <select 
      value={fontSize} 
      onChange={(e) => setFontSize(e.target.value, { days: 365 })}
    >
      <option value="14">Small</option>
      <option value="16">Medium</option>
      <option value="18">Large</option>
    </select>
  );
}
Enter fullscreen mode Exit fullscreen mode

3. GDPR Consent 🏛️

function CookieBanner() {
  const { value: consent, set: setConsent } = useCookie("cookie_consent");

  if (consent) return null;

  return (
    <div className="banner">
      <p>We use cookies 🍪</p>
      <button onClick={() => setConsent("accepted", { days: 365 })}>
        Accept
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

🚀 Advanced Features

Cross-Tab Synchronization

Our useCookie hook automatically syncs cookie changes across browser tabs using the storage event. No more stale data!

// Inside useCookie hook
useEffect(() => {
  const handler = () => {
    setCookieValue(ClientCookies.get(name) ?? defaultValue ?? null);
  };
  window.addEventListener("storage", handler);
  return () => window.removeEventListener("storage", handler);
}, [name, defaultValue]);
Enter fullscreen mode Exit fullscreen mode

Object Storage

While cookies only store strings, we can easily handle objects:

// Store object
const userSettings = { darkMode: true, notifications: false };
ClientCookies.set("settings", JSON.stringify(userSettings));

// Retrieve
const settings = JSON.parse(ClientCookies.get("settings") || "{}");

// With hook
const { value: settings } = useCookie("settings");
const parsedSettings = JSON.parse(settings || "{}");
Enter fullscreen mode Exit fullscreen mode

📝 Troubleshooting Tips

If your cookies aren't behaving:

  1. Check the path 🌐 - Is it set correctly?
  2. Verify secure flag 🔒 - Especially in production
  3. Inspect cookie in browser 🔍 - Chrome DevTools > Application > Cookies
  4. Test cross-tab behavior ↔️ - Change in one tab, check another

Now go forth and manage those cookies like a pro! Just remember, unlike real cookies, these ones won't make you gain weight. 🏋️‍♂️

Pro Tip: Keep your actual cookies (the edible ones) away from your keyboard while coding. I speak from experience. 🍪💻

Comments 0 total

    Add comment