Skip to content

RFC: Server Context for React Server Components #33088

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

kirchoni
Copy link

@kirchoni kirchoni commented May 1, 2025

This RFC proposes reintroducing Server Context for React Server Components to provide a way to share values across components (including async components) without prop drilling.

Motivation

Server Components introduce async rendering patterns which seems to require a specialized context solution. The absence of such a mechanism causes several problems:

  1. Prop drilling becomes unavoidable - Even components that don't need certain data must receive and forward it
  2. Component composition becomes difficult - Deep hierarchies require threading props through every level
  3. Third-party libraries face unique challenges - UI component libraries cannot use global state and need self-contained ways to share configuration

This is especially problematic for component library authors who:

  • Cannot rely on global application state
  • Need to share configuration across complex component hierarchies
  • Must remain encapsulated and independent of application-specific globals

Proposed Solution

A set of APIs specifically designed for Server Components:

function createServerContext<T>(defaultValue: T, displayName?: string): ServerContext<T>;
function useServerContext<T>(context: ServerContext<T>): T;

Implementation

The implementation leverages Node.js's AsyncLocalStorage to maintain context across async boundaries:

  1. Server Context uses a distinct $$typeof symbol (REACT_SERVER_CONTEXT_TYPE)
  2. Values are stored in a Map within AsyncLocalStorage
  3. The API maintains React's familiar Provider pattern while handling async operations seamlessly

AsyncLocalStorage is already used successfully in React for resource resolution in server rendering, making it a proven solution for this purpose.

Key Use Cases

  • Component configuration - Complex UI components (DataGrids, etc.) can share settings across their hierarchy
  • Multi-tenant UI - Different sections of an app can use different theme/locale settings
  • Server resources - Authentication, request data, and database connections can be available throughout the tree

Performance Considerations

AsyncLocalStorage has minimal overhead and is optimized in Node.js:

  • Creates small, short-lived map instances
  • Only updates at render time, not during request processing
  • Offers better performance characteristics than alternatives like prop drilling

Drawbacks

  • Server-only API - requires distinct patterns from client components
  • Requires AsyncLocalStorage or equivalent in the runtime
  • Adds complexity to the React API surface

Alternatives Considered

  1. Prop drilling (status quo)
  2. Global mutable state (violates React principles)
  3. Function composition (deviates from component model)
  4. Client components with regular Context (loses RSC benefits)

Unresolved Questions

  1. Serialization strategy for hydration
  2. Interaction with Suspense boundaries
  3. Support for non-Node.js environments
  4. Potential bridge mechanisms to Client Context

References

@simprl
Copy link

simprl commented May 2, 2025

Thank you for raising this important topic and creating this pull request!

I completely agree with the motivation section. Without a proper context solution, Server Components will not be practical to use. Consider a simple example: I have a library with components. When rendered in the header, they should receive one set of props, but when rendered in the body, a different one. In this scenario, the context isn't about state management, but rather about knowing exactly where in the component tree the component is rendered - thus avoiding unnecessary prop drilling.

Additionally, it might be beneficial to keep the naming consistent (without the word "Server") to facilitate seamless migration of components between server and client environments. If unified naming isn't feasible, I suggest focusing naming conventions around the meaning of contexts - specifically distinguishing between contexts "without state change" and "with state change." For instance, a name like createRenderContext would clearly indicate that the context provides information about the component’s position within the render tree, irrespective of state changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants