Server & Execution
Rendering
Deployment & Operations
Authentication & Data
Environment Functions
What Are Environment Functions?#
Environment functions are utilities designed to define and control function execution based on the runtime environment—whether the code is running on the client or the server. These utilities help ensure that environment-specific logic is executed safely and intentionally, preventing runtime errors and improving maintainability in fullstack or isomorphic applications.
Start provides three core environment functions:
- createIsomorphicFn: Compose a single function that adapts to both client and server environments.
- createServerOnlyFn: Create a function that can only run on the server.
- createClientOnlyFn: Create a function that can only run on the client.
Isomorphic Functions#
Use createIsomorphicFn() to define functions that behave differently depending on whether they are called on the client or the server. This is useful for safely sharing logic across environments while delegating environment-specific behavior to appropriate handlers.
Complete Implementation#
import { createIsomorphicFn } from '@tanstack/react-start'
const getEnv = createIsomorphicFn()
.server(() => 'server')
.client(() => 'client')
const env = getEnv()
// ℹ️ On the **server**, it returns `'server'`.
// ℹ️ On the **client**, it returns `'client'`.Partial Implementation (Server)#
Here is an example of createIsomorphicFn() with only server implementation:
import { createIsomorphicFn } from '@tanstack/react-start'
const serverImplementationOnly = createIsomorphicFn().server(() => 'server')
const server = serverImplementationOnly()
// ℹ️ On the **server**, it returns `'server'`.
// ℹ️ On the **client**, it is no-op (returns `undefined`)Partial Implementation (Client)#
Here is an example of createIsomorphicFn() with only client implementation:
import { createIsomorphicFn } from '@tanstack/react-start'
const clientImplementationOnly = createIsomorphicFn().client(() => 'client')
const client = clientImplementationOnly()
// ℹ️ On the **server**, it is no-op (returns `undefined`)
// ℹ️ On the **client**, it returns `'client'`.No Implementation#
Here is an example of createIsomorphicFn() without any environment specific implementation:
import { createIsomorphicFn } from '@tanstack/react-start'
const noImplementation = createIsomorphicFn()
const noop = noImplementation()
// ℹ️ On both **client** and **server**, it is no-op (returns `undefined`)What is a no-op?#
A no-op (short for "no operation") is a function that does nothing when executed - it simply returns undefined without performing any operations.
// basic no-op implementation
function noop() {}envOnly Functions#
The createServerOnlyFn and createClientOnlyFn helpers enforce strict environment-bound execution. They ensure the returned function is only callable in the correct runtime context. If misused, they throw descriptive runtime errors to prevent unintentional logic execution.
createServerOnlyFn#
import { createServerOnlyFn } from '@tanstack/react-start'
const foo = createServerOnlyFn(() => 'bar')
foo() // ✅ On server: returns "bar"
// ❌ On client: throws "createServerOnlyFn() functions can only be called on the server!"createClientOnlyFn#
import { createClientOnlyFn } from '@tanstack/react-start'
const foo = createClientOnlyFn(() => 'bar')
foo() // ✅ On client: returns "bar"
// ❌ On server: throws "createClientOnlyFn() functions can only be called on the client!"Note
These functions are useful for API access, filesystem reads, using browser APIs, or other operations that are invalid or insecure outside their intended environment.
Tree Shaking#
Environment functions are tree-shaken based on the environment for each bundle produced.
Functions created using createIsomorphicFn() are tree-shaken. All codes inside .client() are not included in server bundle, and vice-versa.
On the server, functions created using createClientOnlyFn() are replaced with a function that throws an Error on the server. The reverse is true for createServerOnlyFn functions on the client.
Troubleshooting#
A loader works on refresh but throws during navigation#
If a loader throws createServerOnlyFn() functions can only be called on the server! after clicking a link, check whether it calls a server-only helper directly. Route loaders also run in the browser during client navigation. createServerOnlyFn guards a local function, it does not send a request to the server.
Wrap the server work in createServerFn and call that function from the loader:
import { createFileRoute } from '@tanstack/react-router'
import { createServerFn, createServerOnlyFn } from '@tanstack/react-start'
const readOnlyOnServer = createServerOnlyFn(() => 'Read on the server')
const readThroughRpc = createServerFn().handler(() => readOnlyOnServer())
export const Route = createFileRoute('/example')({
loader: () => readThroughRpc(),
})The server function runs directly during SSR and makes a request to the server when called in the browser. Test both a direct page request and navigation from another route. A successful refresh alone does not exercise the browser loader.
The execution-boundary tests include the failing direct call and the working server-function version. See Server Functions for validation and middleware when the function accepts user input.
Browser code throws window is not defined on the server#
This means browser-only code ran during server execution. Use the stack trace to find the first application or dependency module that reads window, document, or another browser API.
For a browser-only component, render it inside ClientOnly from @tanstack/react-router with a useful fallback. The Start compiler removes its children from the server bundle, which lets the bundler remove imports used only by those children. The ClientOnly example covers a component that reads window at module scope, and its tests check the server fallback and hydrated content.
A browser API used elsewhere, such as a route loader or server function, still needs the correct execution boundary. Move component side effects into an effect or event handler. For logic that needs different server and browser implementations, use createIsomorphicFn with both implementations. Wrapping a function in createClientOnlyFn does not defer its call until the browser, calling that wrapper on the server throws the client-only guard error instead.
If the stack points into build tooling or the error persists in a minimal app with the correct boundary, include that app and the installed Start and bundler versions in a bug report. A compiler or dependency bug needs a reproducible fix, not a blanket change to rendering mode.