Server Configuration
createServerHttp() is the factory for Node.js and SSR code. It wraps createHttp() with cookie forwarding, tracing, and metrics pre-enabled — and it auto-detects TanStack Start's request context out of the box.
import { createServerHttp } from "rhttp.io/server";
const http = createServerHttp({
baseURL: "https://api.example.com",
timeout: 30_000,
});
// Cookie forwarding, tracing, and prod metrics are already on.
const { data } = await http.get<User>("/protected-api");Signature
function createServerHttp(config?: CreateHttpConfig): HttpClientInstance;It accepts the same CreateHttpConfig shape as the core factory.
What it configures for you
1. Cookie forwarding — forwardCookies: true
The server factory sets auth.forwardCookies to true, which tells the core engine to copy the incoming request's Cookie header into every outbound request whenever a request context is available.
// Internally:
createHttp({
...config,
auth: {
forwardCookies: true,
...config.auth,
},
});2. Observability — logger, tracing, metrics
Server requests are logged by default, traced with a unique x-request-id, and collect metrics in production.
// Internally:
createHttp({
...config,
observability: {
logger: true,
tracing: true,
metrics: process.env.NODE_ENV === "production",
...config.observability,
},
});3. Automatic cookie forwarding interceptor
Beyond the forwardCookies flag, createServerHttp() registers a request interceptor that extracts cookies from the active request context and injects them into each outbound request's Cookie header. This works even without the async_hooks store.
The interceptor resolves the current request through two strategies, tried in priority order:
// Strategy 1: Explicit requestContext function from config.
if (config.requestContext && !request) {
try {
request = config.requestContext();
} catch {
// Ignore — not in request context yet.
}
}
// Strategy 2: TanStack Start auto-detection (optional dependency).
if (!request) {
try {
const module = await import("@tanstack/react-start/server");
if (module?.getRequest) {
request = module.getRequest();
}
} catch {
// TanStack Start not installed or not in a server function — skip.
}
}
// Inject cookies into outbound request.
if (request && typeof request.headers?.get === "function") {
const cookieHeader = request.headers.get("cookie");
if (cookieHeader) {
options.headers = options.headers || {};
options.headers["cookie"] = cookieHeader;
}
}TanStack Start integration
The simplest setup. TanStack Start is auto-detected — no explicit requestContext needed.
// src/lib/http.ts
import { createServerHttp } from "rhttp.io/server";
export const http = createServerHttp({
baseURL: "https://api.example.com",
timeout: 30_000,
});// src/routes/users.tsx
import { createServerFn } from "@tanstack/react-start";
import { http } from "~/lib/http";
export const getUsers = createServerFn({ method: "GET" }).handler(async () => {
const { data } = await http.get<User[]>("/users");
return data;
});When getUsers runs on the server, the interceptor dynamically imports @tanstack/react-start/server, calls getRequest(), and forwards the browser's cookies to your API — session cookies, CSRF tokens, everything.
Using withRequest for explicit context
For frameworks that use Node's async_hooks (or when you need to manually propagate the request), use withRequest():
import { createServerHttp } from "rhttp.io/server";
import { setRequestContextStore } from "rhttp.io/server";
import { AsyncLocalStorage } from "node:async_hooks";
const store = new AsyncLocalStorage();
setRequestContextStore(store);
const http = createServerHttp({ baseURL: "https://api.example.com" });
// In your middleware / route handler:
app.get("/data", async (req, res) => {
return store.run(req, async () => {
const { data } = await http.get("/protected");
res.json(data);
});
});Express / generic Node.js
If you're not using TanStack Start, pass a requestContext function that returns the current request:
import { createServerHttp } from "rhttp.io/server";
const http = createServerHttp({
baseURL: "https://api.example.com",
requestContext: () => currentRequest,
});Or manage context with withRequest as shown above.
Production configuration
import { createServerHttp } from "rhttp.io/server";
export const http = createServerHttp({
baseURL: process.env.INTERNAL_API_URL!,
timeout: 30_000,
// Resilience on unreliable internal networks.
retry: { attempts: 3, strategy: "exponential", delay: 500, maxDelay: 10_000 },
circuitBreaker: {
enabled: true,
failureThreshold: 10,
successThreshold: 3,
timeout: 60_000,
},
requestPool: { enabled: true, maxConcurrent: 10, queueLimit: 50 },
// SSR usually needs fresh data — network-first is safe.
cache: { enabled: false },
// Observability (logger/tracing already on by default).
observability: { metrics: true }, // already true in production
});Summary of server defaults
| Option | Default value | Can override? |
|---|---|---|
auth.forwardCookies | true | ✅ |
observability.logger | true | ✅ |
observability.tracing | true | ✅ |
observability.metrics | process.env.NODE_ENV === "production" | ✅ |
| Cookie interceptor | auto-registered | ✅ |
| TanStack Start detection | auto (dynamic import) | n/a |
Related
- Client Configuration — the browser counterpart.
- Advanced Features — interceptors, auth, caching, retry.
- React & TanStack Query — SSR queries with
useQuery. - API Reference:
createHttp()— full option surface.