---
status: "published"
label: "User Workspace API"
order: 3
title: "User Workspace API | Next.js Supabase SaaS Kit"
description: "Access personal workspace data in MakerKit layouts. Load user account information, subscription status, and account switcher data with the User Workspace API."
---
The User Workspace API provides personal account context for pages under `/home/(user)`. It loads user data, subscription status, and all accounts the user belongs to, making this information available to both server and client components.
{% sequence title="User Workspace API Reference" description="Access personal workspace data in layouts and components" %}
[loadUserWorkspace (Server)](#loaduserworkspace-server)
[useUserWorkspace (Client)](#useuserworkspace-client)
[Data structure](#data-structure)
[Usage patterns](#usage-patterns)
{% /sequence %}
## loadUserWorkspace (Server)
Loads the personal workspace data for the authenticated user. Use this in Server Components within the `/home/(user)` route group.
```tsx
import { loadUserWorkspace } from '~/home/(user)/_lib/server/load-user-workspace';
export default async function PersonalDashboard() {
const data = await loadUserWorkspace();
return (
Welcome, {data.user.email}
Account: {data.workspace.name}
);
}
```
### Function signature
```tsx
async function loadUserWorkspace(): Promise
```
### Caching behavior
The function uses React's `cache()` to deduplicate calls within a single request. You can call it multiple times in nested components without additional database queries.
```tsx
// Both calls use the same cached data
const layout = await loadUserWorkspace(); // First call: hits database
const page = await loadUserWorkspace(); // Second call: returns cached data
```
{% callout title="Performance consideration" %}
While calls are deduplicated within a request, the data is fetched on every navigation. If you only need a subset of the data (like subscription status), consider making a more targeted query.
{% /callout %}
---
## useUserWorkspace (Client)
Access the workspace data in client components using the `useUserWorkspace` hook. The data is provided through React Context from the layout.
```tsx
'use client';
import { useUserWorkspace } from '@kit/accounts/hooks/use-user-workspace';
export function ProfileCard() {
const { workspace, user, accounts } = useUserWorkspace();
return (
{workspace.picture_url && (
)}
{workspace.name}
{user.email}
{workspace.subscription_status && (
Plan: {workspace.subscription_status}
)}
);
}
```
{% callout type="warning" title="Context requirement" %}
The `useUserWorkspace` hook only works within the `/home/(user)` route group where the context provider is set up. Using it outside this layout will throw an error.
{% /callout %}
---
## Data structure
### UserWorkspaceData
```tsx
import type { User } from '@supabase/supabase-js';
interface UserWorkspaceData {
workspace: {
id: string | null;
name: string | null;
picture_url: string | null;
public_data: Json | null;
subscription_status: SubscriptionStatus | null;
};
user: User;
accounts: Array<{
id: string | null;
name: string | null;
picture_url: string | null;
role: string | null;
slug: string | null;
}>;
}
```
### subscription_status values
| Status | Description |
|--------|-------------|
| `active` | Active subscription |
| `trialing` | In trial period |
| `past_due` | Payment failed, grace period |
| `canceled` | Subscription canceled |
| `unpaid` | Payment required |
| `incomplete` | Setup incomplete |
| `incomplete_expired` | Setup expired |
| `paused` | Subscription paused |
### accounts array
The `accounts` array contains all accounts the user belongs to, including:
- Their personal account
- Team accounts where they're a member
- The user's role in each account
This data powers the account switcher component.
---
## Usage patterns
### Personal dashboard page
```tsx
import { loadUserWorkspace } from '~/home/(user)/_lib/server/load-user-workspace';
export default async function DashboardPage() {
const { workspace, user, accounts } = await loadUserWorkspace();
const hasActiveSubscription =
workspace.subscription_status === 'active' ||
workspace.subscription_status === 'trialing';
return (