Service bindings
Call another of your projects on the same server over loopback.
Configuration
"services": [{ "binding": "PEER", "service": "quote-service" }]
Usage
export default {
async fetch(request, env, ctx) {
const response = await env.PEER.fetch(new Request("https://peer/random"));
return response;
},
} satisfies ExportedHandler<Env>;
service is the target project’s name. The call goes to the server’s edge over loopback with the target’s hostname, so it uses the same routing, process pool and logs as a public request. It does not leave the server, so the outbound allowlist does not apply. From compatibility date 2026-10-22, fetch() on a binding returns a Promise, as on Workers; await it at every date.
Calling a method over RPC
From compatibility date 2026-11-18, a project written as a WorkerEntrypoint can be called by method, as on Workers. The callee exports the class:
import { WorkerEntrypoint } from "cloudflare:workers";
export default class QuoteService extends WorkerEntrypoint<Env> {
async fetch(request: Request): Promise<Response> {
return new Response("quote-service");
}
// Callable from a service binding as `await env.PEER.random()`.
async random(): Promise<{ content: string; author: string }> {
return { content: "Simplicity is prerequisite for reliability.", author: "Edsger Dijkstra" };
}
}
The caller awaits the method:
interface Quotes {
random(): Promise<{ content: string; author: string }>;
}
export default {
async fetch(request, env, ctx) {
const quote = await (env.PEER as FetcherAsync<Quotes>).random();
return Response.json(quote);
},
} satisfies ExportedHandler<Env>;
sproutboat types types a service binding as FetcherAsync, which has fetch. It cannot read another project’s classes, so name the methods you call with the type argument, as above. See Generated types.
Constraints
Related
- Outbound fetch: for calls that leave the server