Skip to main content
Version: 11.x

HTTP Link / httpLink

httpLink is a terminating link that sends a tRPC operation to a tRPC procedure over HTTP.

httpLink supports both POST and GET requests and provides several key capabilities:

  • Sending FormData for file uploads and form submissions
  • Handling custom response types like Response objects for advanced use cases (file downloads, streams, etc.)
  • Standard JSON responses for regular API calls

You likely want to combine this link with httpBatchLink or httpBatchStreamLink using a by splitLink to handle different types of operations in your app.

Usage

You can import and add the httpLink to the links array as such:

client/index.ts
ts
import { createTRPCClient, httpLink } from '@trpc/client';
import type { AppRouter } from '../server';
const client = createTRPCClient<AppRouter>({
links: [
httpLink({
url: 'http://localhost:3000',
// transformer,
}),
],
});
client/index.ts
ts
import { createTRPCClient, httpLink } from '@trpc/client';
import type { AppRouter } from '../server';
const client = createTRPCClient<AppRouter>({
links: [
httpLink({
url: 'http://localhost:3000',
// transformer,
}),
],
});

Key Features

FormData Support

httpLink allows you to send FormData directly to your procedures, making it ideal for file uploads and form submissions:

tip

Prerequisites for the example below: Install zod and zod-form-data

npm install zod zod-form-data
ts
import { publicProcedure, router } from './server';
import { processFileStream } from './utils';
import { z } from 'zod';
import { zfd } from 'zod-form-data';
 
const appRouter = router({
uploadFile: publicProcedure
.input(
zfd.formData({
file: zfd.file(),
})
)
.mutation(async (opts) => {
// ...
}),
});
ts
import { publicProcedure, router } from './server';
import { processFileStream } from './utils';
import { z } from 'zod';
import { zfd } from 'zod-form-data';
 
const appRouter = router({
uploadFile: publicProcedure
.input(
zfd.formData({
file: zfd.file(),
})
)
.mutation(async (opts) => {
// ...
}),
});
client.ts
ts
const formData = new FormData();
formData.append('file', fileInput.files[0]);
// Send FormData to your procedure
const result = await client.uploadFile.mutate(formData);
client.ts
ts
const formData = new FormData();
formData.append('file', fileInput.files[0]);
// Send FormData to your procedure
const result = await client.uploadFile.mutate(formData);

Custom Response Types

When your server procedures return Response objects, httpLink can handle various response types including:

  • File downloads
  • Streams
  • Returning custom content types
  • Special headers
ts
// Server procedure returning a custom Response
const appRouter = t.router({
downloadFile: publicProcedure.query(() => {
return new Response('Hello World', {
headers: {
'Content-Type': 'text/plain',
'Content-Disposition': 'attachment; filename="hello.txt"',
},
});
}),
});
// Client usage
const response = await client.downloadFile.query();
// response is a Response object you can handle accordingly
ts
// Server procedure returning a custom Response
const appRouter = t.router({
downloadFile: publicProcedure.query(() => {
return new Response('Hello World', {
headers: {
'Content-Type': 'text/plain',
'Content-Disposition': 'attachment; filename="hello.txt"',
},
});
}),
});
// Client usage
const response = await client.downloadFile.query();
// response is a Response object you can handle accordingly

The httpLink function takes an options object that has the HTTPLinkOptions shape.

ts
export interface HTTPLinkOptions {
url: string;
/**
* Add ponyfill for fetch
*/
fetch?: typeof fetch;
/**
* Add ponyfill for AbortController
*/
AbortController?: typeof AbortController | null;
/**
* Data transformer
* @see https://trpc.io/docs/v11/data-transformers
**/
transformer?: DataTransformerOptions;
/**
* Headers to be set on outgoing requests or a callback that of said headers
* @see http://trpc.io/docs/v10/header
*/
headers?:
| HTTPHeaders
| ((opts: { op: Operation }) => HTTPHeaders | Promise<HTTPHeaders>);
/**
* Send all requests as POSTS requests regardless of the procedure type
* The server must separately allow overriding the method. See:
* @see https://trpc.io/docs/rpc
*/
methodOverride?: 'POST';
}
ts
export interface HTTPLinkOptions {
url: string;
/**
* Add ponyfill for fetch
*/
fetch?: typeof fetch;
/**
* Add ponyfill for AbortController
*/
AbortController?: typeof AbortController | null;
/**
* Data transformer
* @see https://trpc.io/docs/v11/data-transformers
**/
transformer?: DataTransformerOptions;
/**
* Headers to be set on outgoing requests or a callback that of said headers
* @see http://trpc.io/docs/v10/header
*/
headers?:
| HTTPHeaders
| ((opts: { op: Operation }) => HTTPHeaders | Promise<HTTPHeaders>);
/**
* Send all requests as POSTS requests regardless of the procedure type
* The server must separately allow overriding the method. See:
* @see https://trpc.io/docs/rpc
*/
methodOverride?: 'POST';
}

Reference

You can check out the source code for this link on GitHub.