Skip to content

Shared State Management

How τjs handles shared code and state across multiple applications.

τjs supports sharing code between apps through build-time composition. State sharing happens through:

  • Shared code modules (compiled into each bundle)
  • Persistent storage (localStorage, cookies, databases)
  • Server-side data (SSR hydration, API calls)

Key principle: Each app runs in its own runtime. There is no shared memory between apps at runtime.

Create a shared directory for code used across apps:

client/
├── shared/
│ ├── store/ # Shared state stores
│ │ ├── theme.store.ts
│ │ └── user.store.ts
│ ├── components/ # Shared UI components
│ │ ├── Button.tsx
│ │ └── Header.tsx
│ ├── hooks/ # Shared React hooks
│ │ └── useAuth.ts
│ └── utils/ # Shared utilities
│ └── formatting.ts
├── app/ # Customer app
└── admin/ # Admin app

When τjs builds each app:

  1. Shared code is compiled into each app’s bundle
  2. Tree-shaking removes unused exports
  3. Each app gets its own copy of the compiled code
  4. No runtime coordination between apps

Example:

shared/store/theme.store.ts
import { create } from "zustand";
import { persist } from "zustand/middleware";
export const useThemeStore = create(
persist(
(set) => ({
theme: "light" as "light" | "dark",
setTheme: (theme: "light" | "dark") => set({ theme }),
}),
{
name: "app-theme", // localStorage key
}
)
);
client/app/App.tsx
import { useThemeStore } from "@shared/store/theme.store";
export function App() {
const { theme, setTheme } = useThemeStore();
return (
<div className={theme}>
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
Toggle Theme
</button>
</div>
);
}
client/admin/App.tsx
import { useThemeStore } from "@shared/store/theme.store";
export function App() {
const { theme } = useThemeStore();
return <div className={theme}>Admin content</div>;
}

How it works:

  1. Build time: theme.store.ts compiled into both bundles
  2. Runtime: Each app has its own store instance
  3. Persistence: Both stores read/write same localStorage key
  4. Result: Theme persists across page navigation between apps

Share state via browser localStorage:

shared/store/preferences.store.ts
import { create } from "zustand";
import { persist } from "zustand/middleware";
interface Preferences {
language: string;
timezone: string;
theme: "light" | "dark";
}
export const usePreferencesStore = create(
persist<Preferences>(
(set) => ({
language: "en",
timezone: "UTC",
theme: "light",
setLanguage: (language: string) => set({ language }),
setTimezone: (timezone: string) => set({ timezone }),
setTheme: (theme: "light" | "dark") => set({ theme }),
}),
{
name: "user-preferences",
}
)
);

Lifecycle:

Customer App localStorage Admin App
──────────── ─────────── ─────────
User toggles sidebar → Update storage → (Not yet loaded)
Navigate to admin → Read storage → Sidebar state restored

For server-accessible state, use cookies:

shared/utils/cookies.ts
export function setCookie(name: string, value: string, days: number = 365) {
const expires = new Date(Date.now() + days * 864e5).toUTCString();
document.cookie = `${name}=${encodeURIComponent(
value
)}; expires=${expires}; path=/; SameSite=Lax`;
}
export function getCookie(name: string): string | null {
return (
document.cookie
.split("; ")
.find((row) => row.startsWith(`${name}=`))
?.split("=")[1] || null
);
}
shared/store/session.store.ts
import { create } from "zustand";
import { getCookie, setCookie } from "@shared/utils/cookies";
export const useSessionStore = create((set) => ({
sessionId: getCookie("session_id"),
setSessionId: (sessionId: string) => {
setCookie("session_id", sessionId);
set({ sessionId });
},
}));

Load state from server on each app load:

taujs.config.ts
{
path: '/app/:page*',
attr: {
render: 'ssr',
middleware: { auth: {} },
data: async (params, ctx) => ({
serviceName: 'UserPreferencesService',
serviceMethod: 'getPreferences',
args: { userId: ctx.user.id }
})
}
}
{
path: '/admin/:section*',
attr: {
render: 'ssr',
middleware: { auth: {} },
data: async (params, ctx) => ({
serviceName: 'UserPreferencesService',
serviceMethod: 'getPreferences',
args: { userId: ctx.user.id }
})
}
}
services/user-preferences.service.ts
export const UserPreferencesService = defineService({
getPreferences: async (params: { userId: string }, ctx) => {
const prefs = await db.userPreferences.findUnique({
where: { userId: params.userId },
});
return {
theme: prefs.theme,
language: prefs.language,
timezone: prefs.timezone,
};
},
});
client/app/App.tsx
import { useSSRStore } from "@taujs/react";
import { usePreferencesStore } from "@shared/store/preferences.store";
import { useEffect } from "react";
export function App() {
const serverData = useSSRStore();
const { setTheme, setLanguage } = usePreferencesStore();
// Sync server data to client store
useEffect(() => {
if (serverData.theme) setTheme(serverData.theme);
if (serverData.language) setLanguage(serverData.language);
}, [serverData]);
return <div>App content</div>;
}

UI/UX preferences:

const useThemeStore = create(/* theme state */);
const useLanguageStore = create(/* language state */);
const useLayoutStore = create(/* layout preferences */);

Authentication state:

const useAuthStore = create(/* auth token, user info */);

Feature flags:

const useFeatureFlagsStore = create(/* enabled features */);

Shared UI components:

export { Button, Card, Modal } from "@shared/components";

Utility functions:

export { formatDate, formatCurrency, parseJSON } from "@shared/utils";

Customer app state:

client/app/store/cart.store.ts
const useCartStore = create(/* cart items */);

Admin app state:

client/admin/store/admin-users.store.ts
const useAdminUsersStore = create(/* admin user list */);

Why: Domain-specific state doesn’t need to persist between apps.

import { useThemeStore } from "@shared/store/theme.store";
describe("ThemeStore", () => {
beforeEach(() => {
// Reset store before each test
useThemeStore.setState({ theme: "light" });
});
it("toggles theme", () => {
const { setTheme } = useThemeStore.getState();
setTheme("dark");
expect(useThemeStore.getState().theme).toBe("dark");
setTheme("light");
expect(useThemeStore.getState().theme).toBe("light");
});
});
import { usePreferencesStore } from "@shared/store/preferences.store";
describe("Preferences Persistence", () => {
beforeEach(() => {
localStorage.clear();
});
it("persists preferences to localStorage", () => {
const { setTheme, setLanguage } = usePreferencesStore.getState();
setTheme("dark");
setLanguage("es");
// Verify localStorage
const stored = JSON.parse(localStorage.getItem("user-preferences") || "{}");
expect(stored.state.theme).toBe("dark");
expect(stored.state.language).toBe("es");
});
});

Only share what’s necessary:

// ✅ Good - share UI preferences
const useThemeStore = create(/* ... */);
// ❌ Bad - sharing domain logic
const useOrderProcessingStore = create(/* ... */);
// ✅ Good - localStorage for client-only
persist({ name: "ui-preferences" });
// ✅ Good - cookies for server-accessible
setCookie("session_id", value);
// ✅ Good - database for important data
UserPreferencesService.save(preferences);
// ✅ Good - fallback values
const { theme = "light" } = useThemeStore();
// ✅ Good - null checks
const preferences = useSSRStore();
if (preferences.theme) {
setTheme(preferences.theme);
}
/**
* Theme store - shared across all apps
*
* Persisted to localStorage as 'app-theme'
* Used by: customer app, admin app, marketing site
*
* @example
* const { theme, setTheme } = useThemeStore();
*/
export const useThemeStore = create(/* ... */);