Node.js platform abstractions and utilities for Remix applications
—
Complete re-export of @remix-run/server-runtime providing unified access to all Remix server functionality including request handling, response utilities, data fetching, and error handling.
Creates a request handler for processing Remix application requests.
/**
* Creates a request handler for a Remix application
* @param build - The server build configuration
* @returns RequestHandler function for processing requests
*/
function createRequestHandler(build: ServerBuild): RequestHandler;
interface RequestHandler {
(request: Request, loadContext?: AppLoadContext): Promise<Response>;
}Usage Examples:
import { createRequestHandler } from "@remix-run/node";
import * as build from "./build/index.js";
// Create request handler
const handleRequest = createRequestHandler(build);
// Use with Express
app.all("*", async (req, res) => {
const request = new Request(`http://localhost:3000${req.url}`, {
method: req.method,
headers: req.headers,
body: req.method !== "GET" && req.method !== "HEAD" ? req.body : undefined
});
const response = await handleRequest(request);
res.status(response.status);
response.headers.forEach((value, name) => {
res.header(name, value);
});
if (response.body) {
response.body.pipeTo(new WritableStream({
write(chunk) {
res.write(chunk);
},
close() {
res.end();
}
}));
} else {
res.end();
}
});Utilities for creating various types of responses in Remix applications.
/**
* Creates a JSON response with proper headers
* @param object - The object to serialize as JSON
* @param init - Optional response initialization options
* @returns TypedResponse with JSON content
*/
function json<T>(object: T, init?: ResponseInit): TypedResponse<T>;
/**
* Creates a deferred response for streaming data
* @param object - Object containing promises to be resolved
* @param init - Optional response initialization options
* @returns TypedDeferredData for streaming
*/
function defer<T>(object: T, init?: ResponseInit): TypedDeferredData<T>;
/**
* Creates a redirect response
* @param url - The URL to redirect to
* @param init - Status code (302) or ResponseInit object
* @returns Redirect response
*/
function redirect(url: string, init?: number | ResponseInit): Response;
/**
* Creates a document redirect response
* @param url - The URL to redirect to
* @param init - Status code or ResponseInit object
* @returns Document redirect response
*/
function redirectDocument(url: string, init?: number | ResponseInit): Response;
/**
* Creates a replace response (replaces current history entry)
* @param url - The URL to replace with
* @param init - Status code or ResponseInit object
* @returns Replace response
*/
function replace(url: string, init?: number | ResponseInit): Response;
/**
* Creates a data response (legacy utility)
* @param object - The data to include in the response
* @param init - Optional response initialization options
* @returns Response with data
*/
function data<T>(object: T, init?: ResponseInit): Response;Usage Examples:
import { json, defer, redirect, data } from "@remix-run/node";
// JSON response
export async function loader({ params }: LoaderFunctionArgs) {
const user = await getUserById(params.userId);
if (!user) {
return json({ error: "User not found" }, { status: 404 });
}
return json({ user });
}
// Deferred response for streaming
export async function loader({ params }: LoaderFunctionArgs) {
// Fast data
const user = await getUserById(params.userId);
// Slow data (streamed later)
const postsPromise = getPostsByUserId(params.userId);
const commentsPromise = getCommentsByUserId(params.userId);
return defer({
user, // Available immediately
posts: postsPromise, // Streamed when ready
comments: commentsPromise // Streamed when ready
});
}
// Redirect responses
export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData();
const intent = formData.get("intent");
if (intent === "delete") {
await deleteUser(String(formData.get("userId")));
return redirect("/users");
}
if (intent === "update") {
await updateUser(String(formData.get("userId")), formData);
return redirectDocument(`/users/${formData.get("userId")}`);
}
return redirect("/");
}Utilities for working with sessions and cookies.
/**
* Creates a new session instance
* @param initialData - Optional initial session data
* @param id - Optional session ID
* @returns New session instance
*/
function createSession<Data = SessionData, FlashData = Data>(
initialData?: Partial<Data>,
id?: string
): Session<Data, FlashData>;
/**
* Type guard to check if an object is a Cookie
* @param object - Object to check
* @returns True if object is a Cookie
*/
function isCookie(object: any): object is Cookie;
/**
* Type guard to check if an object is a Session
* @param object - Object to check
* @returns True if object is a Session
*/
function isSession(object: any): object is Session;Utilities for handling file uploads in Remix applications.
/**
* Composes multiple upload handlers into a single handler
* @param handlers - Array of upload handlers to compose
* @returns Composed upload handler
*/
function unstable_composeUploadHandlers(
...handlers: UploadHandler[]
): UploadHandler;
/**
* Creates a memory-based upload handler
* @param options - Configuration options for memory upload handler
* @returns UploadHandler that stores files in memory
*/
function unstable_createMemoryUploadHandler(
options?: MemoryUploadHandlerOptions
): UploadHandler;
/**
* Parses multipart form data using specified upload handlers
* @param request - The request containing multipart form data
* @param uploadHandler - Handler for processing uploaded files
* @returns Promise resolving to FormData with processed uploads
*/
function unstable_parseMultipartFormData(
request: Request,
uploadHandler: UploadHandler
): Promise<FormData>;Usage Examples:
import {
unstable_composeUploadHandlers,
unstable_createMemoryUploadHandler,
unstable_parseMultipartFormData,
unstable_createFileUploadHandler
} from "@remix-run/node";
// Compose multiple upload handlers
const uploadHandler = unstable_composeUploadHandlers(
// Try file handler first for large files
unstable_createFileUploadHandler({
directory: "/tmp/uploads",
filter: ({ filename, contentType }) => {
return filename && contentType.startsWith("image/");
}
}),
// Fall back to memory handler for small files
unstable_createMemoryUploadHandler({
maxPartSize: 100000 // 100KB
})
);
// Use in action
export async function action({ request }: ActionFunctionArgs) {
const formData = await unstable_parseMultipartFormData(
request,
uploadHandler
);
const avatar = formData.get("avatar") as File;
const document = formData.get("document") as File;
return json({
avatar: avatar?.name,
document: document?.name
});
}Utilities for development and debugging in Remix applications.
/**
* Broadcasts a development ready signal
* @param build - The server build
* @param options - Optional broadcast options
*/
function broadcastDevReady(build: ServerBuild, options?: any): void;
/**
* Logs a development ready message
* @param build - The server build
*/
function logDevReady(build: ServerBuild): void;The server runtime provides comprehensive TypeScript types for all Remix server functionality:
// Core function types
type ActionFunction<Context = AppLoadContext> = (
args: ActionFunctionArgs<Context>
) => Promise<Response> | Response | Promise<any> | any;
type LoaderFunction<Context = AppLoadContext> = (
args: LoaderFunctionArgs<Context>
) => Promise<Response> | Response | Promise<any> | any;
interface ActionFunctionArgs<Context = AppLoadContext> {
request: Request;
params: Params;
context: Context;
}
interface LoaderFunctionArgs<Context = AppLoadContext> {
request: Request;
params: Params;
context: Context;
}
// Response types
interface TypedResponse<T = unknown> extends Response {
json(): Promise<T>;
}
interface TypedDeferredData<T = Record<string, unknown>> {
data: T;
init?: ResponseInit;
}
// Error handling
interface ErrorResponse {
status: number;
statusText: string;
data: any;
}
// Meta and headers functions
type MetaFunction<
Loader extends LoaderFunction | unknown = unknown,
ParentsLoaders extends Record<string, LoaderFunction> = {}
> = (args: MetaArgs<Loader, ParentsLoaders>) => MetaDescriptor[];
type HeadersFunction = (args: HeadersArgs) => Headers | HeadersInit;
type LinksFunction = () => LinkDescriptor[];
// Session and cookie types
interface SessionData {
[key: string]: any;
}
interface Cookie {
readonly name: string;
readonly isSigned: boolean;
readonly expires?: Date;
parse(cookieHeader?: string | null): Promise<any>;
serialize(value: any): Promise<string>;
}
// Upload handler types
type UploadHandler = (args: UploadHandlerPart) => Promise<File | string | null | undefined>;
interface UploadHandlerPart {
name: string;
filename?: string;
contentType: string;
data: AsyncIterable<Uint8Array>;
}Error Classes:
/**
* Error thrown when upload part size exceeds the configured limit
*/
class MaxPartSizeExceededError extends Error {
constructor(field: string, maxPartSize: number);
}This comprehensive server runtime API provides all the tools needed to build full-featured Remix applications with proper error handling, data loading, form processing, file uploads, and session management.
Install with Tessl CLI
npx tessl i tessl/npm-remix-run--node