npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

orbo

v3.4.2

Published

Minimal, lazy-initialized global state for React. Zero nested providers, true bundle splitting, useState-familiar API

Readme

Orbo

npm version bundle size

Orbo

Minimal, lazy-initialized global state for React. Zero nested providers, true bundle splitting, useState-familiar API

Why Orbo?

React applications inevitably accumulate global state: dark mode, user preferences, feature flags, A/B tests. The traditional solution creates a maintenance nightmare of nested Context providers:

<DomainProvider>
  <FeaturesProvider>
    <PreferencesProvider>
      <CartProvider>
        <ModalProvider>
          <YourApp />

Every new feature adds another provider, every page loads all state logic regardless of usage, and your _app.tsx becomes a dumping ground for cross-team dependencies

Orbo takes a different approach: What if global state was as easy as useState, automatically lazy initialized, and completely decoupled from your app shell?

Built from the ground up for modern React applications that demand both performance and developer experience. 140 lines of code. Zero dependencies. TypeScript-first

[!WARNING] Orbo is designed specifically for singleton global states (dark mode, user preferences, feature flags, ...) -> It is not a full state management solution like Redux or Zustand

Features

  • 🚫 Zero nested providers - Single GlobalStateProvider replaces all provider nesting
  • 📦 True bundle splitting - State code loads only when components that use it render
  • useState-familiar API - const count = useCount() and setCount(5) - that's it
  • 🔒 SSR safe - No hydration mismatches, no useEffect hacks
  • 🎯 TypeScript first - Compile-time safety with module augmentation
  • 🪶 Minimal - 140 lines, zero dependencies, tree-shakeable

Installation

npm install orbo

Quick Start

import { createGlobalState, GlobalStateProvider } from "orbo";

// State definition stays with your component - not in _app.tsx
const [useCount, useSetCount] = createGlobalState({
  initialState: () => 0,
});

function Counter() {
  const count = useCount();
  const setCount = useSetCount();

  return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}

function App() {
  return (
    <GlobalStateProvider initialValues={{}}>
      <Counter />
    </GlobalStateProvider>
  );
}

That's it. No provider nesting, no complex setup, no _app.tsx modifications.

Real-World Examples

Simple Dark Mode

Here's how you'd handle a typical dark mode implementation:

// useDarkMode.ts - lives with your component, not in _app.tsx
import { createGlobalState } from "orbo";

const [useDarkMode, useSetDarkMode] = createGlobalState({
  initialState: ({ cookies }) => cookies.darkMode === "true",
});

export { useDarkMode, useSetDarkMode };

// DarkModeToggle.tsx
import { useDarkMode, useSetDarkMode } from "./useDarkMode";

export function DarkModeToggle() {
  const isDark = useDarkMode();
  const setDarkMode = useSetDarkMode();

  return (
    <button onClick={() => setDarkMode(!isDark)}>{isDark ? "🌙" : "☀️"}</button>
  );
}

// _app.tsx - clean and minimal
function App({ pageProps, cookies }) {
  return (
    <GlobalStateProvider initialValues={{ cookies }}>
      <Component {...pageProps} />
    </GlobalStateProvider>
  );
}

Server Time with Auto-Update

Here's a more complex example showing lifecycle management with onSubscribe and persistState:

// useServerTime.ts
import { createGlobalState } from "orbo";

const [useServerTime, useSetServerTime] = createGlobalState({
  initialState: ({ serverTime }) => new Date(serverTime),
  onSubscribe: (setState) => {
    // Start timer when first component subscribes
    const interval = setInterval(() => {
      setState(new Date());
    }, 1000);

    // Return cleanup function
    return () => {
      clearInterval(interval);
    };
  },
  // Cleanup timer when no components are using this state
  persistState: false,
});

export { useServerTime };

// Clock.tsx
import { useServerTime } from "./useServerTime";

export function Clock() {
  const time = useServerTime();

  return <div>Current time: {time.toLocaleTimeString()}</div>;
}

// _app.tsx
function App({ pageProps }) {
  return (
    <GlobalStateProvider initialValues={{ serverTime: Date.now() }}>
      <Component {...pageProps} />
    </GlobalStateProvider>
  );
}

In these examples, the logic is completely decoupled from your app shell. Components that don't use the state never load its code. New developers can understand and modify features without touching _app.tsx

TypeScript Support

Orbo provides compile-time safety through module augmentation (same pattern as styled-components):

// types.ts
// Import to enable module augmentation
import "orbo";
declare module "orbo" {
  interface GlobalStateInitialValues {
    cookies: { darkMode?: string };
    user: { id: string; name: string } | null;
    hostname: string;
  }
}

// Now your initialState functions are fully typed
const [useUser] = createGlobalState({
  initialState: (initialValues) => {
    // initialValues.user <- TypeScript knows this exists and its shape
    // initialValues.invalidProp <- TypeScript error!
    return initialValues.user;
  },
});

Architecture

Orbo's design is based on three key insights:

  1. Lazy Initialization: State code should only be initialized when the components that use it actually render
  2. Decoupling: State definitions should live with components, not in central configuration files
  3. Explicit Contracts: Dependencies should be compile-time safe, not runtime discoveries

This results in:

  • Better performance through automatic code splitting
  • Better maintainability through colocation
  • Better reliability through TypeScript contracts

API Reference

createGlobalState<T>(config)

Creates a pair of hooks for reading and writing global state.

const [useValue, useSetValue] = createGlobalState({
  initialState: (initialValues) => computeInitialValue(initialValues),

  // Optional: sync with external sources (client-side only)
  onSubscribe: (setState, currentState) => {
    // Subscribe to external changes
    // Optional: return cleanup function
    return () => {
      // Cleanup when last component unsubscribes
    };
  },

  // Optional: keep state in memory when components unmount
  persistState: true, // (default)
});

Parameters:

  • config.initialState: Function that receives initial values and isHydrated flag, returns the initial state
  • config.onSubscribe (optional): Function called when first component subscribes (client-side only). Receives setState and currentState. Can return a cleanup function which runs when the last component unsubscribes
  • config.persistState (optional): When true, keeps state in memory after components unmount (default: true)

Handling Client-Only Values with isHydrated

When working with client-only APIs like localStorage, sessionStorage, or browser APIs that aren't available during server-side rendering, there is the isHydrated parameter to optimize initial state handling

In general it is best practices NOT to mix SSR with client-only state as doing so creates hydrarion mismatches issues

Use the isHydrated flag only as a last resort when you absolutely must read from client-only APIs:

const [useTheme] = createGlobalState({
  initialState: (initialValues, isHydrated) => {
    if (!isHydrated) {
      // During SSR and initial hydration: use server value to avoid mismatch
      return 'light';
    }
    // After hydration: safe to use client-only APIs
    return localStorage.getItem('theme') || 'light';
  }
});

Returns:

  • [useGlobalState, useSetGlobalState] - React hooks for reading and writing the state

GlobalStateProvider

Root provider that manages state isolation and provides initial values

<GlobalStateProvider initialValues={{ cookies, user }}>
  {children}
</GlobalStateProvider>

Props:

  • initialValues: Object containing initial values passed to initialState functions
  • children: React children

Examples

Check out the /examples directory for complete implementations:

  • Dark Mode - Theme switching with cookie persistence
  • User State - Authentication state management
  • Feature Flags - A/B testing and feature toggling

License

MIT