< PHP MASTER />

Global State in Next.js Using React Context, Zustand with Persistent and Without Persistent

In modern Next.js applications, managing global state is a common requirement.Whether it’s authentication data, user preferences, theme settings, or temporary UI state, having a centralized and scalable solution is essential.

Sajid Ali13-01-20266 min read

In this guide, we will learn how to use global state in Next.js using both React Context API and Zustand. React Context is the official way provided by React, while Zustand is a lightweight external library that can also work outside of React’s component lifecycle.

Why Do We Need Global State in Nextjs?

Before jumping into implementation, it’s important to understand why global state is needed.

Before Global State in Next.js (Prop Drilling Problem)

Consider a component structure where data is created in Component One, but needs to be accessed in Component Six.

Sajid Ali

Without global state, we are forced to pass the same data through Component Two, Three, Four, and Five using props—even though those components do not actually need the data.

This problem is known as prop drilling. It leads to unnecessary coupling, poor maintainability, and makes refactoring difficult as the application grows.

After Global State

With global state, data is stored in a centralized place. Any component—whether it is Component Six or any other—can directly access and update the state without passing props through intermediate components.

Sajid Ali

This results in cleaner code, better scalability, and easier maintenance.

Implementation of Global State in Nextjs

Let’s now understand how to implement global state in Next.js using React Context API and Zustand, along with persistent and non-persistent approaches.

Watch the Practical Implementation

Prefer learning by watching? Follow along with a complete step-by-step walkthrough of this Global State implementation in nextjs, including both temporary and persistent state examples.

Watch Video

1. React Context API

React Context API is the official way to manage global state in React. It works well for authentication state, themes, and shared application data.

Create Context

js
"use client";

import { createContext, useContext, useState } from "react";

const AuthContext = createContext(null);

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);

  return (
    <AuthContext.Provider value={{ user, setUser }}>
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error("useAuth must be used inside AuthProvider");
  }
  return context;
}

Wrap Context in Layout

js
// app/admin/layout.js
import { AuthProvider } from "@/context/AuthContext";

export default function AdminLayout({ children }) {
  return (
    <AuthProvider>
      {children}
    </AuthProvider>
  );
}

Using Context in Components

js
"use client";
import { useAuth } from "@/context/AuthContext";

export default function AdminPage() {
  const { user, setUser } = useAuth();

  return (
    <div>
      {user ? (
        <>
          <p>Welcome, {user.name}</p>
          <button onClick={() => setUser(null)}>Logout</button>
        </>
      ) : (
        <button onClick={() => setUser({ name: "Sajid Ali" })}>
          Login
        </button>
      )}
    </div>
  );
}

When setUser is called in one component, the updated state is automatically reflected across all components using the context.

However, one limitation exists: after a page refresh, the state is lost.

Adding Persistence with localStorage

To prevent data loss on page reload, we can persist the state usinglocalStorage.

js
"use client";

import { createContext, useContext, useState, useEffect } from "react";

const AuthContext = createContext(null);

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    const savedUser = localStorage.getItem("authUser");
    if (savedUser) {
      setUser(JSON.parse(savedUser));
    }
  }, []);

  useEffect(() => {
    if (user) {
      localStorage.setItem("authUser", JSON.stringify(user));
    } else {
      localStorage.removeItem("authUser");
    }
  }, [user]);

  return (
    <AuthContext.Provider value={{ user, setUser }}>
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  return useContext(AuthContext);
}

- Important Notes -

  • Never store sensitive data like tokens, passwords, or user private information in localStorage
  • Prefer HttpOnly cookies for authentication tokens to prevent XSS attacks
  • Use localStorage only for UI settings, themes, carts, or user preferences

2. Zustand

Zustand is a lightweight state management library and a popular alternative to Redux. It works outside React’s component tree and supports persistence using middleware.

Create Zustand in Nextjs Component

js
import { create } from "zustand";

export const useGlobalStateZustand = create(
  (set) => ({
    user: null,
    setUser: (user) => set({ user }),
    
  }),
);

Zustand allows accessing and mutating state without prop drilling and can even be used inside plain JavaScript classes.

Using Zustand in Nextjs

js
"use client";
import { useGlobalState } from "@/context/useGlobalState";
import { useRouter } from "next/navigation";

export default function Page() {
  const { user, setUser } = useGlobalState(); // and get user has data, after set
  const router = useRouter();
  const loginUser = ()=>{
    setUser({ name: "Sajid Ali", phone_no:7065221377} )
    router.push("/dashboard");
  }
  return (
    <div className="d-flex justify-content-center align-items-enter mt-4">
        <button className="btn btn-lg btn-primary" onClick={()=>{loginUser()}} >
          Login
        </button>
    </div>
  );
}

Using Zustand in Outside Nextjs Component or In Server Side Component

js
import { useGlobalStateZustand } from "@/lib/useGlobalStateZustand";
export class UserService {
    static setUser({name, phone_no}){
        const state = useGlobalStateZustand.getState();
        return state.setUser({name, phone_no})
    }
}
js
"use client";
import { UserService } from "@/service/UserService";
export default function (){
    const result = UserService.setUser({name:"PHPMaster", phone_no:"7065221377"});
    return "hello";
}

Zustand Persistence in Nextjs

js
import { create } from "zustand";
import { persist } from "zustand/middleware";
export const useGlobalStateZustand = create(
  persist((set) => ({
    user: null,
    setUser: (user) => set({ user }),
  }),
  {
    name:"userZustand"
  }
)
);

Zustand allows accessing and mutating state without prop drilling and can even be used inside plain JavaScript classes.

- Important Notes -

  • Never store sensitive data like tokens, passwords, or user private information in localStorage
  • Prefer HttpOnly cookies for authentication tokens to prevent XSS attacks
  • Use localStorage only for UI settings, themes, carts, or user preferences

Conclusion

Both React Context API and Zustand are excellent choices for global state management in Next.js. Context is ideal for simple and official solutions, while Zustand shines in performance-critical and complex applications.

Understanding the when to use temporary state and when to persist data is key to building scalable, maintainable, and user-friendly applications.

Frequently Asked Questions

Global state is shared data that can be accessed across multiple components in a Next.js application without passing props manually. It is commonly used for authentication, themes, user preferences, and shared UI data.
React Context is ideal for simple global state like authentication, themes, or language settings. Zustand is better for complex applications that require better performance and frequent state updates.
Yes, Zustand can be accessed outside React components using getState(). This allows it to be used in utility functions, service classes, or server-side logic.
No, storing authentication tokens in localStorage is not recommended because it is vulnerable to XSS attacks. Secure HttpOnly cookies are considered a safer alternative.
Global state can be persisted using localStorage or Zustand persist middleware. However, persistence should only be used for non-sensitive data such as UI settings, themes, or shopping carts.
Yes, many applications use React Context for simple global state and Zustand for complex or performance-heavy state management.
Tags:
Global State Next.jsReact Context APIZustandZustand Persistent
Sajid Ali

Author

Sajid Ali

Software Developer

Software developer passionate about writing clean, scalable, and maintainable code. Focused on building elegant user interfaces and great developer experiences.