# What Is the Role of SWR in the Plane Frontend?

> Discover how SWR powers the Plane frontend with efficient data fetching, automatic caching, and background revalidation. Optimize your app's performance with the useSWR hook.

- Repository: [Plane/plane](https://github.com/makeplane/plane)
- Tags: deep-dive
- Published: 2026-08-22

---

**SWR (stale-while-revalidate) serves as the centralized data-fetching backbone for Plane’s React frontend, providing automatic caching, background revalidation, and error retry logic through the `useSWR` hook and shared configurations in [`packages/constants/src/swr.ts`](https://github.com/makeplane/plane/blob/main/packages/constants/src/swr.ts).**

Plane leverages SWR to unify server-state management across its open-source project management interface. By abstracting API logic into reusable hooks and centralized configuration files, the codebase eliminates redundant network requests while ensuring the UI remains responsive and immediately populated with cached data.

## Centralized Configuration Architecture

All SWR instances in Plane inherit from shared defaults defined in [`packages/constants/src/swr.ts`](https://github.com/makeplane/plane/blob/main/packages/constants/src/swr.ts). This centralization ensures consistent caching behavior and network policies across the entire application.

### Default vs. Web Configurations

The repository exports two distinct configuration objects that cater to different data freshness requirements:

- **`DEFAULT_SWR_CONFIG`** – Optimized for internal API calls where background refreshes are unnecessary. This configuration minimizes network traffic by disabling automatic revalidation when the tab regains focus or when the cache is stale.

- **`WEB_SWR_CONFIG`** – Designed for public-facing components such as workspace lists and notification feeds where data must remain fresh.

```typescript
// packages/constants/src/swr.ts
export const DEFAULT_SWR_CONFIG = {
  refreshWhenHidden: false,
  revalidateIfStale: false,
  revalidateOnFocus: false,
  revalidateOnMount: true,
  refreshInterval: 600_000,
  errorRetryCount: 3,
};

```

By importing these constants wherever `useSWR` is instantiated, Plane maintains a single source of truth for data-fetching behavior, according to the Plane source code.

## Data Flow and Caching Mechanisms

When components wrap API calls with `useSWR`, Plane guarantees three core behaviors that optimize the user experience:

1. **Instant Caching** – The first successful response is stored locally, allowing subsequent renders to read from cache immediately without loading states.

2. **Stale-While-Revalidate Updates** – The UI displays cached data instantly while a background request fetches fresh data. Once the new data resolves, React automatically re-renders the component with updated values.

3. **Robust Error Handling** – The shared `errorRetryCount` parameter prevents infinite refetch loops by limiting retries to three attempts before surfacing the error to the UI.

## Integration Points Across the UI

SWR is woven throughout Plane’s component hierarchy, from authentication wrappers to infinite-scrolling integrations.

### Authentication and User State

The [`apps/web/core/lib/wrappers/authentication-wrapper.tsx`](https://github.com/makeplane/plane/blob/main/apps/web/core/lib/wrappers/authentication-wrapper.tsx) file demonstrates how SWR bootstraps the user session. It fetches current user data using a stable key that persists across route changes:

```tsx
// apps/web/core/lib/wrappers/authentication-wrapper.tsx
const { isLoading: isUserSWRLoading } = useSWR(
  "USER_INFORMATION",
  async () => await fetchCurrentUser(),
  WEB_SWR_CONFIG
);

```

This pattern ensures that user information remains available globally without prop drilling, while `WEB_SWR_CONFIG` keeps the session data fresh throughout the application lifecycle.

### Workspace and Project Management

Domain-specific wrappers like [`workspace-wrapper.tsx`](https://github.com/makeplane/plane/blob/main/workspace-wrapper.tsx) and [`project-wrapper.tsx`](https://github.com/makeplane/plane/blob/main/project-wrapper.tsx) utilize SWR to fetch hierarchical data. Components such as [`views-list.tsx`](https://github.com/makeplane/plane/blob/main/views-list.tsx) and [`members-list.tsx`](https://github.com/makeplane/plane/blob/main/members-list.tsx) follow the same pattern, passing workspace slugs as cache keys to isolate data per context:

```tsx
import useSWR from "swr";
import { DEFAULT_SWR_CONFIG } from "@plane/constants";

const fetchUserProjects = async (workspaceSlug: string) => {
  const resp = await fetch(`/api/workspaces/${workspaceSlug}/projects`);
  return resp.json();
};

export const ProjectList = ({ workspaceSlug }: { workspaceSlug: string }) => {
  const { data, error, isLoading } = useSWR(
    [`PROJECTS_${workspaceSlug}`],
    () => fetchUserProjects(workspaceSlug),
    DEFAULT_SWR_CONFIG
  );

  if (isLoading) return <Spinner />;
  if (error) return <ErrorMsg>{error.message}</ErrorMsg>;

  return (
    <ul>
      {data?.map((proj: any) => (
        <li key={proj.id}>{proj.name}</li>
      ))}
    </ul>
  );
};

```

### Infinite Scrolling with useSWRInfinite

For paginated data such as GitHub repository listings, Plane imports `useSWRInfinite` from `swr/infinite`. As implemented in [`apps/web/core/components/integration/github/select-repository.tsx`](https://github.com/makeplane/plane/blob/main/apps/web/core/components/integration/github/select-repository.tsx), the hook manages cursor-based pagination by checking `previousPageData` to determine if additional pages exist:

```tsx
import useSWRInfinite from "swr/infinite";

const getKey = (pageIndex: number, previousPageData: any) => {
  if (previousPageData && !previousPageData.length) return null;
  return `/api/github/repos?page=${pageIndex + 1}`;
};

const GithubRepoSelect = () => {
  const { data, size, setSize, isValidating } = useSWRInfinite(getKey, fetcher);
  const repos = data?.flat() ?? [];

  return (
    <Select
      options={repos}
      onScrollEnd={() => setSize(size + 1)}
      loading={isValidating}
    />
  );
};

```

## Performance Optimization Strategies

Plane fine-tunes SWR’s behavior to balance data freshness against network congestion. By setting `refreshWhenHidden` and `revalidateOnFocus` to `false` in `DEFAULT_SWR_CONFIG`, the application avoids redundant API calls when users switch tabs or return to inactive windows.

For critical real-time features like notification badges, components switch to `WEB_SWR_CONFIG`, enabling background updates:

```tsx
import useSWR from "swr";
import { WEB_SWR_CONFIG } from "@plane/constants";

const fetchNotifications = async () => {
  const resp = await fetch("/api/notifications");
  return resp.json();
};

export const NotificationBell = () => {
  const { data: notifications, isLoading } = useSWR(
    "USER_NOTIFICATIONS",
    fetchNotifications,
    WEB_SWR_CONFIG
  );

  return (
    <Badge count={notifications?.length ?? 0}>
      {isLoading ? <Spinner size="sm" /> : <BellIcon />}
    </Badge>
  );
};

```

The ten-minute `refreshInterval` (600,000ms) provides a safety net for long-lived sessions without overwhelming the backend infrastructure.

## Summary

- **SWR** provides the data-fetching backbone for Plane’s React frontend through the `useSWR` and `useSWRInfinite` hooks.
- Centralized configurations in [`packages/constants/src/swr.ts`](https://github.com/makeplane/plane/blob/main/packages/constants/src/swr.ts) enforce consistent caching and retry policies across the application.
- `DEFAULT_SWR_CONFIG` optimizes for performance by disabling background refreshes, while `WEB_SWR_CONFIG` ensures real-time updates for critical UI elements.
- Authentication wrappers, workspace loaders, and paginated GitHub integrations all rely on SWR’s automatic revalidation and error handling.
- Strategic use of cache keys and configuration flags minimizes network usage while maintaining data freshness.

## Frequently Asked Questions

### How does Plane configure SWR for different data freshness requirements?

Plane maintains two exported configuration objects in [`packages/constants/src/swr.ts`](https://github.com/makeplane/plane/blob/main/packages/constants/src/swr.ts). `DEFAULT_SWR_CONFIG` disables background revalidation (`revalidateIfStale: false`, `revalidateOnFocus: false`) for standard API calls, while `WEB_SWR_CONFIG` enables real-time updates for public-facing components like notification feeds and workspace lists.

### Where does Plane handle user authentication state with SWR?

The [`apps/web/core/lib/wrappers/authentication-wrapper.tsx`](https://github.com/makeplane/plane/blob/main/apps/web/core/lib/wrappers/authentication-wrapper.tsx) file fetches the current user session using `useSWR` with the cache key `"USER_INFORMATION"` and the `WEB_SWR_CONFIG` configuration. This ensures user data remains fresh across navigation while providing a global loading state for authentication checks.

### How does Plane implement pagination for external integrations like GitHub?

Plane utilizes `useSWRInfinite` from the `swr` package in components such as [`apps/web/core/components/integration/github/select-repository.tsx`](https://github.com/makeplane/plane/blob/main/apps/web/core/components/integration/github/select-repository.tsx). The implementation defines a `getKey` function that checks `previousPageData` to terminate pagination when no more results exist, while `setSize` triggers additional page fetches during scroll events.

### What error handling mechanisms does SWR provide in the Plane frontend?

Through the centralized `errorRetryCount: 3` setting in `DEFAULT_SWR_CONFIG`, SWR automatically retries failed requests up to three times before returning an error to the component. This prevents infinite refetch loops and provides consistent error states across the UI without manual try-catch blocks in every component.