Skip to content
rest-rpc
Esc
navigateopen⌘Jpreview
On this page

Fetch Client With Next.js

Use the fetch client with Next.js server-side cache tags.

Use @rest-rpc/next when calling a REST API from Next.js server code. As long as you describe the API with a rest-rpc contract, the backend itself can be implemented with any framework or language.

It wraps the core fetch client and can attach deterministic tags to GET requests through Next’s fetch options.

Install

pnpm add @rest-rpc/core @rest-rpc/next

Create A Next Client

import { initNextClient } from "@rest-rpc/next";
import { api } from "./contract";

export const client = initNextClient(api, {
	origin: process.env.API_BASE_URL!,
	automaticFetchTags: {
		enabled: true,
	},
});

Use this client from Server Components, Server Actions, route handlers, or other server-side Next.js code.

export default async function TodoPage({
	params,
}: {
	params: Promise<{ id: string }>;
}) {
	const { id } = await params;
	const todo = await client.todos.get.fetch({ id });

	return <h1>{todo.title}</h1>;
}

Automatic Tags

Automatic tags are added to GET requests only. Existing next options and manual tags are preserved.

const todo = await client.todos.get.fetch(
	{ id: "todo_1", filter: "open" },
	{
		next: {
			revalidate: 60,
			tags: ["manual"],
		},
	},
);

For a request like /todos/todo_1?filter=open, the client attaches both the exact tag and the broader path tag.

[
	"rest-rpc:/todos/todo_1?filter=open",
	"rest-rpc:/todos/todo_1",
]

The exact tag invalidates one query variant. The path tag invalidates cached GET requests for that path across query variants.

Use tagPrefix when one Next app talks to multiple APIs.

export const client = initNextClient(api, {
	origin: process.env.API_BASE_URL!,
	automaticFetchTags: {
		enabled: true,
		tagPrefix: "admin-api",
	},
});

Revalidate After Mutations

Use getRouteCacheTags() when a mutation, Server Action, route handler, or webhook needs to invalidate data loaded through the fetch client.

"use server";

import { revalidateTag } from "next/cache";
import { getRouteCacheTags } from "@rest-rpc/core";
import { api } from "./contract";
import { client } from "./client";

export async function renameTodo(id: string, title: string) {
	await client.todos.update.fetch({ id, title });

	for (const tag of getRouteCacheTags(api.todos.get, { request: { id } })) {
		revalidateTag(tag);
	}
}

getRouteCacheTags() is exported from @rest-rpc/core, so non-Next backends can generate the same invalidation tags for webhooks or queues.

Was this page helpful?