0
# Isomorphic Functions
1
2
Isomorphic functions allow you to create functions with different implementations for client and server environments. This enables code that adapts to its execution context, providing optimal behavior on both sides of your application.
3
4
## Capabilities
5
6
### Create Isomorphic Function
7
8
Creates a function that can have different implementations on the client and server, with implementations defaulting to no-op functions when not provided.
9
10
```typescript { .api }
11
/**
12
* Creates an isomorphic function with different client/server implementations
13
* @returns IsomorphicFnBase for chaining client/server implementations
14
*/
15
function createIsomorphicFn(): IsomorphicFnBase;
16
17
interface IsomorphicFnBase {
18
/** Define the server-side implementation */
19
server<TArgs extends Array<any>, TServer>(
20
serverImpl: (...args: TArgs) => TServer
21
): ServerOnlyFn<TArgs, TServer>;
22
23
/** Define the client-side implementation */
24
client<TArgs extends Array<any>, TClient>(
25
clientImpl: (...args: TArgs) => TClient
26
): ClientOnlyFn<TArgs, TClient>;
27
}
28
```
29
30
**Usage Examples:**
31
32
```typescript
33
import { createIsomorphicFn } from "@tanstack/react-start";
34
35
// Logging function with different implementations
36
const log = createIsomorphicFn()
37
.server((message: string) => {
38
// Server-side: log to console with timestamp
39
console.log(`[${new Date().toISOString()}] ${message}`);
40
})
41
.client((message: string) => {
42
// Client-side: log to browser console
43
console.log(`[CLIENT] ${message}`);
44
});
45
46
// Storage function with different backends
47
const getItem = createIsomorphicFn()
48
.server((key: string) => {
49
// Server-side: use environment variables or file system
50
return process.env[key] || null;
51
})
52
.client((key: string) => {
53
// Client-side: use localStorage
54
return localStorage.getItem(key);
55
});
56
```
57
58
### Create Server-Only Function
59
60
Creates a function that only executes on the server, with the option to add a client-side implementation later.
61
62
```typescript { .api }
63
/**
64
* Creates a server-only function with optional client implementation
65
* @param serverImpl - The server-side implementation
66
* @returns ServerOnlyFn that can be extended with client implementation
67
*/
68
function createServerOnlyFn<TArgs extends Array<any>, TServer>(
69
serverImpl: (...args: TArgs) => TServer
70
): ServerOnlyFn<TArgs, TServer>;
71
72
interface ServerOnlyFn<TArgs extends Array<any>, TServer>
73
extends IsomorphicFn<TArgs, TServer> {
74
/** Add a client-side implementation */
75
client<TClient>(
76
clientImpl: (...args: TArgs) => TClient
77
): IsomorphicFn<TArgs, TServer, TClient>;
78
}
79
```
80
81
**Usage Examples:**
82
83
```typescript
84
import { createServerOnlyFn } from "@tanstack/react-start";
85
86
// Database access function (server-only by default)
87
const getUser = createServerOnlyFn((id: string) => {
88
// Server-side: access database
89
return db.user.findUnique({ where: { id } });
90
});
91
92
// Add client-side fallback
93
const getUserWithFallback = createServerOnlyFn((id: string) => {
94
return db.user.findUnique({ where: { id } });
95
}).client((id: string) => {
96
// Client-side: fetch from API
97
return fetch(`/api/users/${id}`).then(r => r.json());
98
});
99
```
100
101
### Create Client-Only Function
102
103
Creates a function that only executes on the client, with the option to add a server-side implementation later.
104
105
```typescript { .api }
106
/**
107
* Creates a client-only function with optional server implementation
108
* @param clientImpl - The client-side implementation
109
* @returns ClientOnlyFn that can be extended with server implementation
110
*/
111
function createClientOnlyFn<TArgs extends Array<any>, TClient>(
112
clientImpl: (...args: TArgs) => TClient
113
): ClientOnlyFn<TArgs, TClient>;
114
115
interface ClientOnlyFn<TArgs extends Array<any>, TClient>
116
extends IsomorphicFn<TArgs, undefined, TClient> {
117
/** Add a server-side implementation */
118
server<TServer>(
119
serverImpl: (...args: TArgs) => TServer
120
): IsomorphicFn<TArgs, TServer, TClient>;
121
}
122
```
123
124
**Usage Examples:**
125
126
```typescript
127
import { createClientOnlyFn } from "@tanstack/react-start";
128
129
// Analytics tracking function (client-only by default)
130
const trackEvent = createClientOnlyFn((event: string, data: any) => {
131
// Client-side: send to analytics service
132
analytics.track(event, data);
133
});
134
135
// Add server-side implementation for SSR contexts
136
const trackEventWithServer = createClientOnlyFn((event: string, data: any) => {
137
analytics.track(event, data);
138
}).server((event: string, data: any) => {
139
// Server-side: log for debugging or send to server analytics
140
console.log(`[ANALYTICS] ${event}:`, data);
141
});
142
```
143
144
## Advanced Usage Patterns
145
146
### Environment Detection
147
148
Isomorphic functions automatically detect their execution environment and call the appropriate implementation:
149
150
```typescript
151
import { createIsomorphicFn } from "@tanstack/react-start";
152
153
const getCurrentUrl = createIsomorphicFn()
154
.server(() => {
155
// Server-side: construct URL from request
156
return `${process.env.BASE_URL}/current-page`;
157
})
158
.client(() => {
159
// Client-side: use window.location
160
return window.location.href;
161
});
162
163
// This will call the appropriate implementation based on context
164
const url = getCurrentUrl();
165
```
166
167
### Shared Logic with Environment-Specific Details
168
169
```typescript
170
import { createIsomorphicFn } from "@tanstack/react-start";
171
172
const formatDate = createIsomorphicFn()
173
.server((date: Date) => {
174
// Server-side: use server timezone
175
return date.toLocaleString('en-US', {
176
timeZone: process.env.SERVER_TIMEZONE || 'UTC'
177
});
178
})
179
.client((date: Date) => {
180
// Client-side: use user's timezone
181
return date.toLocaleString();
182
});
183
```
184
185
## Types
186
187
```typescript { .api }
188
// Base isomorphic function type
189
interface IsomorphicFn<
190
TArgs extends Array<any> = [],
191
TServer = undefined,
192
TClient = undefined
193
> {
194
(...args: TArgs): TServer | TClient;
195
}
196
197
// Server-only function with optional client extension
198
interface ServerOnlyFn<TArgs extends Array<any>, TServer>
199
extends IsomorphicFn<TArgs, TServer> {
200
client<TClient>(
201
clientImpl: (...args: TArgs) => TClient
202
): IsomorphicFn<TArgs, TServer, TClient>;
203
}
204
205
// Client-only function with optional server extension
206
interface ClientOnlyFn<TArgs extends Array<any>, TClient>
207
extends IsomorphicFn<TArgs, undefined, TClient> {
208
server<TServer>(
209
serverImpl: (...args: TArgs) => TServer
210
): IsomorphicFn<TArgs, TServer, TClient>;
211
}
212
213
// Base interface for creating isomorphic functions
214
interface IsomorphicFnBase extends IsomorphicFn {
215
server<TArgs extends Array<any>, TServer>(
216
serverImpl: (...args: TArgs) => TServer
217
): ServerOnlyFn<TArgs, TServer>;
218
219
client<TArgs extends Array<any>, TClient>(
220
clientImpl: (...args: TArgs) => TClient
221
): ClientOnlyFn<TArgs, TClient>;
222
}
223
```