Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
title: Access Durable Object jurisdiction via `ctx.id.jurisdiction`
description: Read the jurisdiction of a jurisdiction-restricted Durable Object from within the object itself.
products:
- durable-objects
- workers
date: 2026-03-26
---

`ctx.id.jurisdiction` inside a Durable Object now reports the [jurisdiction](/durable-objects/reference/data-location/#restrict-durable-objects-to-a-jurisdiction) that the object was created in, matching the value seen client-side. If a Worker accesses a Durable Object through a jurisdiction-restricted namespace — for example `env.MY_DURABLE_OBJECT.jurisdiction("eu")` — the same jurisdiction is available on `ctx.id.jurisdiction` inside the object, so you can make region-aware decisions without passing the jurisdiction through method arguments or persisting it in storage.

The `jurisdiction` property was previously gated behind an experimental flag because the value was not consistently available on the `DurableObjectId` exposed inside a Durable Object as `ctx.id`. With this change, `jurisdiction` is generally available and is preserved across every ID-construction path, including:

- IDs created from a jurisdiction-restricted subnamespace, for example `env.MY_DURABLE_OBJECT.jurisdiction("eu").idFromName("foo")` or `.newUniqueId()`.
- IDs created via `env.MY_DURABLE_OBJECT.newUniqueId({ jurisdiction: "eu" })`.
- IDs restored from a string via `idFromString()`, including when restored through the unrestricted namespace binding.
- IDs observed inside [alarm handlers](/durable-objects/api/alarms/) for alarms scheduled on 2026-03-15 or later.

```js
export class RegionalRoom extends DurableObject {
async fetch(request) {
// "eu" when accessed through env.MY_DURABLE_OBJECT.jurisdiction("eu")
const region = this.ctx.id.jurisdiction;
return new Response(`Hello from ${region ?? "the default region"}!`);
}
}

// Worker
export default {
async fetch(request, env) {
const stub = env.MY_DURABLE_OBJECT.jurisdiction("eu").getByName("general");
return stub.fetch(request);
},
};
```

`ctx.id.jurisdiction` is `undefined` for Durable Objects that were not created in a jurisdiction-restricted namespace. Alarms scheduled before 2026-03-15 also do not have `jurisdiction` stored; to backfill the value, reschedule the alarm from a `fetch()` or RPC handler.

For more information, refer to the [Durable Object ID documentation](/durable-objects/api/id/#jurisdiction).
120 changes: 119 additions & 1 deletion src/content/docs/durable-objects/api/id.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,15 @@ assert not id1.equals(id2), "Different unique ids should never be equal."

`name` is an optional property of a `DurableObjectId`, which returns the name that was used to create the `DurableObjectId` via [`DurableObjectNamespace::idFromName`](/durable-objects/api/namespace/#idfromname). This value is undefined if the `DurableObjectId` was constructed using [`DurableObjectNamespace::newUniqueId`](/durable-objects/api/namespace/#newuniqueid).

The `name` property is available on `ctx.id` inside the Durable Object when the caller uses `idFromName()` or `getByName()`. If the caller accesses the Durable Object using `idFromString()`, `ctx.id.name` will be `undefined`, even if the ID was originally created with `idFromName()`. Names longer than 1,024 bytes are not passed through and will be `undefined` on `ctx.id`.
The `name` property is also available on `ctx.id` inside the Durable Object when the caller uses `idFromName()` or `getByName()`. `ctx.id.name` will be `undefined` in the following cases:

- The caller accesses the Durable Object using `idFromString()`, even if the ID was originally created with `idFromName()`.
- Names longer than 1,024 bytes are not passed through to `ctx.id`.
- The Durable Object was created with `newUniqueId()`.

:::tip[Useful for alarms]
`ctx.id.name` is especially useful inside [alarm handlers](/durable-objects/api/alarms/), where there is no calling client to pass the name as an argument. When the alarm fires, `ctx.id.name` holds the same name the object was originally accessed with.
:::

:::note
Alarms created before 2026-03-15 do not have `name` stored. When such an alarm fires, `ctx.id.name` will be `undefined`, and any new alarm scheduled from that handler will also lack a `name`. To fix this, reschedule the alarm from a `fetch()` or RPC handler where `name` is available.
Expand Down Expand Up @@ -115,6 +123,116 @@ assert from_name_id.name == "foo", "name matches parameter to idFromName"

</Tabs>

The same `name` is available inside the Durable Object via `ctx.id.name`:

<Tabs>

<TabItem label="JavaScript" icon="seti:javascript">

```js
import { DurableObject } from "cloudflare:workers";

export class ChatRoom extends DurableObject {
async getRoomName() {
return this.ctx.id.name; // "foo" when accessed via getByName("foo")
}
}
```

</TabItem>

<TabItem label="Python" icon="seti:python">

```python
from workers import DurableObject

class ChatRoom(DurableObject):
async def get_room_name(self):
return self.ctx.id.name # "foo" when accessed via get_by_name("foo")
```

</TabItem>

</Tabs>

### `jurisdiction`

`jurisdiction` is an optional property of a `DurableObjectId`, which returns the [jurisdiction](/durable-objects/reference/data-location/#restrict-durable-objects-to-a-jurisdiction) the ID is restricted to, such as `"eu"` or `"fedramp"`. This value is `undefined` if the `DurableObjectId` was created from a namespace that is not restricted to a jurisdiction.

The `jurisdiction` property is also available on `ctx.id` inside the Durable Object. Unlike `name`, the jurisdiction is preserved across every ID-construction path:

- **Populated** when the ID is created from a jurisdiction-restricted subnamespace returned by `env.MY_DURABLE_OBJECT.jurisdiction("eu")` — for example via `.idFromName("foo")` or `.newUniqueId()`.
- **Populated** when the ID is created with `env.MY_DURABLE_OBJECT.newUniqueId({ jurisdiction: "eu" })`.
- **Populated** after a round-trip through `toString()` and `idFromString()`, including when the ID is restored through the non-restricted namespace binding.
- **Populated** inside [alarm handlers](/durable-objects/api/alarms/) for alarms scheduled on 2026-03-15 or later.
- **`undefined`** for Durable Objects created in a namespace that is not restricted to a jurisdiction.

:::tip[Useful for region-aware logic]
Because `ctx.id.jurisdiction` is available inside the Durable Object — including in `alarm()` handlers and after restoring an ID from a string — you can use it to make region-aware decisions without passing the jurisdiction as an argument or persisting it in storage.
:::

:::note
Alarms created before 2026-03-15 do not have `jurisdiction` stored. When such an alarm fires, `ctx.id.jurisdiction` will be `undefined`, and any new alarm scheduled from that handler will also lack a `jurisdiction`. To fix this, reschedule the alarm from a `fetch()` or RPC handler where `jurisdiction` is available.
:::

<Tabs>

<TabItem label="JavaScript" icon="seti:javascript">

```js
const plainId = env.MY_DURABLE_OBJECT.idFromName("foo");
const euId = env.MY_DURABLE_OBJECT.jurisdiction("eu").idFromName("foo");
console.assert(plainId.jurisdiction === undefined, "no jurisdiction set");
console.assert(euId.jurisdiction === "eu", "jurisdiction matches namespace");
```

</TabItem>

<TabItem label="Python" icon="seti:python">

```python
plain_id = env.MY_DURABLE_OBJECT.idFromName("foo")
eu_id = env.MY_DURABLE_OBJECT.jurisdiction("eu").idFromName("foo")
assert plain_id.jurisdiction is None, "no jurisdiction set"
assert eu_id.jurisdiction == "eu", "jurisdiction matches namespace"
```

</TabItem>

</Tabs>

The same `jurisdiction` is available inside the Durable Object via `ctx.id.jurisdiction`:

<Tabs>

<TabItem label="JavaScript" icon="seti:javascript">

```js
import { DurableObject } from "cloudflare:workers";

export class RegionalRoom extends DurableObject {
async getRegion() {
return this.ctx.id.jurisdiction; // "eu" when created via .jurisdiction("eu")
}
}
```

</TabItem>

<TabItem label="Python" icon="seti:python">

```python
from workers import DurableObject

class RegionalRoom(DurableObject):
async def get_region(self):
return self.ctx.id.jurisdiction # "eu" when created via .jurisdiction("eu")
```

</TabItem>

</Tabs>

## Related resources

- [Durable Objects: Easy, Fast, Correct – Choose Three](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/).
20 changes: 14 additions & 6 deletions src/content/docs/durable-objects/reference/data-location.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,15 @@ Note that it is also possible to specify a jurisdiction by creating an individua

### Supported locations

| Parameter | Location |
| --------- | ---------------------------- |
| eu | The European Union |
| Parameter | Location |
| --------- | ------------------------------ |
| eu | The European Union |
| fedramp | FedRAMP-compliant data centers |

### Read the jurisdiction from inside a Durable Object

The jurisdiction of a Durable Object is available inside the object via [`ctx.id.jurisdiction`](/durable-objects/api/id/#jurisdiction). The value is preserved across `toString()` and `idFromString()` round-trips and is also available inside [alarm handlers](/durable-objects/api/alarms/) for alarms scheduled on 2026-03-15 or later, which makes it suitable for region-aware logic inside the Durable Object.

## Provide a location hint

Durable Objects, as with any stateful API, will often add response latency as requests must be forwarded to the data center where the Durable Object, or state, is located.
Expand Down Expand Up @@ -102,10 +106,14 @@ Hints are a best effort and not a guarantee. Unlike with jurisdictions, Durable
| afr | Africa <sup>2</sup> |
| me | Middle East <sup>2</sup> |

<sup>1</sup> Dynamic relocation of existing Durable Objects is planned for the future.
<sup>1</sup> Dynamic relocation of existing Durable Objects is planned for the
future.

<sup>2</sup> Durable Objects currently do not spawn in this location. Instead, the Durable Object will spawn in a nearby location which does support Durable Objects. For example, Durable Objects hinted to South America spawn in Eastern North America instead.
<sup>2</sup> Durable Objects currently do not spawn in this location. Instead,
the Durable Object will spawn in a nearby location which does support Durable
Objects. For example, Durable Objects hinted to South America spawn in Eastern
North America instead.

## Additional resources

- You can find our more about where Durable Objects are located using the website: [Where Durable Objects Live](https://where.durableobjects.live/).
- You can find our more about where Durable Objects are located using the website: [Where Durable Objects Live](https://where.durableobjects.live/).