Invoking methods on a Durable Object
All new projects and existing projects with a compatibility date greater than or equal to 2024-04-03
should prefer to invoke Remote Procedure Call (RPC) methods defined on a Durable Object class. Legacy projects can continue to invoke the fetch
handler on the Durable Object class indefinitely.
By writing a Durable Object class which inherits from the built-in type DurableObject
, public methods on the Durable Objects class are exposed as RPC methods , which you can call using a DurableObjectStub from a Worker.
All RPC calls are asynchronous , accept and return serializable types , and propagate exceptions to the caller without a stack trace. Refer to Workers RPC for complete details.
import { DurableObject } from "cloudflare:workers" ;
export class MyDurableObject extends DurableObject {
async fetch ( request , env ) {
// Every unique ID refers to an individual instance of the Durable Object class
const id = env . MY_DURABLE_OBJECT . idFromName ( "foo" ) ;
// A stub is a client used to invoke methods on the Durable Object
const stub = env . MY_DURABLE_OBJECT . get ( id ) ;
// Methods on the Durable Object are invoked via the stub
const rpcResponse = await stub . sayHello () ;
return new Response ( rpcResponse ) ;
import { DurableObject } from "cloudflare:workers" ;
MY_DURABLE_OBJECT : DurableObjectNamespace < MyDurableObject >;
export class MyDurableObject extends DurableObject {
constructor ( ctx : DurableObjectState , env : Env ) {
async sayHello () : Promise < string > {
async fetch ( request , env ) {
// Every unique ID refers to an individual instance of the Durable Object class
const id = env . MY_DURABLE_OBJECT . idFromName ( "foo" ) ;
// A stub is a client used to invoke methods on the Durable Object
const stub = env . MY_DURABLE_OBJECT . get ( id ) ;
// Methods on the Durable Object are invoked via the stub
const rpcResponse = await stub . sayHello () ;
return new Response ( rpcResponse ) ;
} satisfies ExportedHandler < Env >;
Note
With RPC, the DurableObject
superclass defines ctx
and env
as class properties. What was previously called state
is now called ctx
when you extend the DurableObject
class. The name ctx
is adopted rather than state
for the DurableObjectState
interface to be consistent between DurableObject
and WorkerEntrypoint
objects.
Refer to Build a Counter for a complete example.
Invoking the fetch
handler
If your project is stuck on a compatibility date before 2024-04-03
, or has the need to send a Request
object and return a Response
object, then you should send requests to a Durable Object via the fetch handler.
import { DurableObject } from "cloudflare:workers" ;
export class MyDurableObject extends DurableObject {
return new Response ( "Hello, World!" ) ;
async fetch ( request , env ) {
// Every unique ID refers to an individual instance of the Durable Object class
const id = env . MY_DURABLE_OBJECT . idFromName ( "foo" ) ;
// A stub is a client used to invoke methods on the Durable Object
const stub = env . MY_DURABLE_OBJECT . get ( id ) ;
// Methods on the Durable Object are invoked via the stub
const response = await stub . fetch ( request ) ;
import { DurableObject } from "cloudflare:workers" ;
MY_DURABLE_OBJECT : DurableObjectNamespace < MyDurableObject >;
export class MyDurableObject extends DurableObject {
constructor ( ctx : DurableObjectState , env : Env ) {
async fetch ( request : Request ) : Promise < Response > {
return new Response ( "Hello, World!" ) ;
async fetch ( request , env ) {
// Every unique ID refers to an individual instance of the Durable Object class
const id = env . MY_DURABLE_OBJECT . idFromName ( "foo" ) ;
// A stub is a client used to invoke methods on the Durable Object
const stub = env . MY_DURABLE_OBJECT . get ( id ) ;
// Methods on the Durable Object are invoked via the stub
const response = await stub . fetch ( request ) ;
} satisfies ExportedHandler < Env >;
The URL
associated with the Request
object passed to the fetch()
handler of your Durable Object must be a well-formed URL, but does not have to be a publicly-resolvable hostname.
Without RPC, customers frequently construct requests which corresponded to private methods on the Durable Object and dispatch requests from the fetch
handler. RPC is obviously more ergonomic in this example.
import { DurableObject } from "cloudflare:workers" ;
export class MyDurableObject extends DurableObject {
constructor ( ctx : DurableObjectState , env : Env ) {
return new Response ( `Hello, ${ name } !` ) ;
return new Response ( `Goodbye, ${ name } !` ) ;
const url = new URL ( request . url ) ;
let name = url . searchParams . get ( "name" ) ;
return this . goodbye ( name ) ;
return new Response ( "Bad Request" , { status : 400 } ) ;
async fetch ( _request , env , _ctx ) {
// Every unique ID refers to an individual instance of the Durable Object class
const id = env . MY_DURABLE_OBJECT . idFromName ( "foo" ) ;
// A stub is a client used to invoke methods on the Durable Object
const stub = env . MY_DURABLE_OBJECT . get ( id ) ;
// Invoke the fetch handler on the Durable Object stub
let response = await stub . fetch ( "http://do/hello?name=World" ) ;
import { DurableObject } from "cloudflare:workers" ;
MY_DURABLE_OBJECT : DurableObjectNamespace < MyDurableObject >;
export class MyDurableObject extends DurableObject {
constructor ( ctx : DurableObjectState , env : Env ) {
private hello ( name : string ) {
return new Response ( `Hello, ${ name } !` ) ;
private goodbye ( name : string ) {
return new Response ( `Goodbye, ${ name } !` ) ;
async fetch ( request : Request ) : Promise < Response > {
const url = new URL ( request . url ) ;
let name = url . searchParams . get ( "name" ) ;
return this . goodbye ( name ) ;
return new Response ( "Bad Request" , { status : 400 } ) ;
async fetch ( _request , env , _ctx ) {
// Every unique ID refers to an individual instance of the Durable Object class
const id = env . MY_DURABLE_OBJECT . idFromName ( "foo" ) ;
// A stub is a client used to invoke methods on the Durable Object
const stub = env . MY_DURABLE_OBJECT . get ( id ) ;
// Invoke the fetch handler on the Durable Object stub
let response = await stub . fetch ( "http://do/hello?name=World" ) ;
} satisfies ExportedHandler < Env >;