> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Shared Actors

> Reach one Stateful Actor type from multiple functions on the same account by declaring the same type under different bindings — the owner ships the class, the reference ships none.

A **shared actor** is a single Stateful Actor type reachable from two or more Edge Compute functions on the same account. The function that ships the actor class **owns** the actor; other functions on the same account declare the same `type` under their own `binding` name and ship **no** class — their binding routes to the owner's actor and its state.

```
┌─────────────────────────┐        ┌─────────────────────────┐
│  Owner function         │        │  Reference function     │
│  (ships Account)        │        │  (ships no class)       │
│                         │        │                         │
│  binding ACCOUNT        │        │  binding READONLY       │
│  type    Account        │        │  type    Account  ←──┐  │
└───────────┬─────────────┘        └───────────┬─────────┘ │
            │                                   │           │
            └───────────────┬───────────────────┘           │
                            ▼                               │
              ┌──────────────────────────────┐             │
              │  Actor: Account              │ ◀── one durable actor
              │   • per-name state           │      two functions
              │   • single-threaded dispatch │
              └──────────────────────────────┘
```

## Why Share an Actor

* **Split read and write paths** into separate functions with their own auth, rate limits, and deploy cadence — without duplicating state.
* **Let a second function call into a domain the first one owns** (e.g., a reporting function reads an account actor that a payments function owns).
* **Keep one durable actor behind many entrypoints.** Both functions talk to the same per-name state; writes through one binding are visible to reads through the other.

Both functions must be on the **same account** — shared actors are bounded by account.

## The Pattern

The owner function is a normal Stateful Actor project — it ships the class. The reference function declares the same `type` under a different `binding` and ships **no** actor class — its binding routes to the owner's actor and state; no second instance is created.

There's no `new-func` flag for "reference-only," so the workflow is: scaffold with `--actor` (to mint a `func_id` and write `telnyx.toml`), then drop the actor class and rename the binding.

## Walkthrough: a Read-Only Account Reference

Prereq: an owner function for the type already shipped on your account (the `account` from the [Quick Start](/docs/edge-compute/stateful-actors/quick-start), type `Account`).

### 1. Mint a `func_id` and scaffold, then drop the class

```bash theme={null}
telnyx-edge new-func --actor --name=account-readonly   # registers the func, writes func_id
cd account-readonly
rm -f src/counter.ts                                    # the ref ships no actor class
```

### 2. Point `telnyx.toml` at the owner's type under a new binding

Edit the `[[actors]]` block — keep `type` equal to the owner's type, change `binding`:

```toml theme={null}
[[actors]]
binding = "READONLY"    # this func's own handle
type    = "Account"     # SAME type the owner declares → shared actor
```

Leave `name`, `main`, `compatibility_date`, and the `[edge_compute]` `func_id` as scaffolded.

### 3. Replace `src/index.ts` with a class-free handler that calls `env.READONLY`

```ts theme={null}
import {
  type ActorNamespace,
  type ActorStub,
  type IdFromNameOptions,
} from "@telnyx/edge-runtime";

// Hand-rolled stub narrowing (mirrors the owner's read surface; no local class).
type AccountStub = ActorStub & {
  balance(): Promise<{ balance: number }>;
};
interface AccountNamespace extends ActorNamespace {
  idFromName(name: string, options?: IdFromNameOptions): AccountStub;
}
interface Env { READONLY: AccountNamespace }   // <- the binding from telnyx.toml

export default {
  async fetch(req: Request, env: Env): Promise<Response> {
    const url = new URL(req.url);
    if (url.pathname === "/health/liveness") return new Response("ok");
    if (url.pathname === "/health/readiness") return new Response("ok");

    // Read-only view: balance for an account
    const m = url.pathname.match(/^\/accounts\/([^/]+)\/balance$/);
    if (m && req.method === "GET") {
      const result = await env.READONLY.idFromName(m[1]!).balance();
      return Response.json({ account: m[1], ...result, via: "READONLY->Account(shared)" });
    }
    return new Response("not found", { status: 404 });
  },
};
```

**Key point:** no `export class Account` in this file. The bundler roots at `main`, so with nothing importing the class, the reference bundle ships class-free (a few KB) — that's what makes it reference-only.

### 4. Install deps and ship (same as the owner)

```bash theme={null}
npm install
telnyx-edge ship
```

### 5. Prove they share one actor

```bash theme={null}
REF=https://account-readonly-<id>.telnyxcompute.com
OWN=https://account-<id>.telnyxcompute.com

# Write via the owner (ACCOUNT binding) — carol is a fresh account name
curl -sS -X POST $OWN/accounts/carol/deposit \
  -H 'content-type: application/json' -d '{"amount":100}'

# Read via the reference (READONLY binding) → same balance
curl -sS $REF/accounts/carol/balance
# → {"account":"carol","balance":100,"via":"READONLY->Account(shared)"}
```

Write through `ACCOUNT`, read through `READONLY`, same `balance` → one durable actor (Account), two functions. Both must be on the same account; the reference's `type` must exactly match the owner's.

## Rules of Thumb

* **Same account, same `type`.** Reference bindings whose `type` doesn't match an owner already on the account won't resolve.
* **Only one function owns the class.** The owner ships the actor class; every other function declares the same `type` and ships no class.
* **Renaming the binding is fine.** Each function picks its own `binding` name — that's the property on `env` for that function. The `type` is what glues them together.
* **Reference bundles are small.** With no class import, the bundler emits a class-free bundle. Keep it that way: don't import the actor class from your reference function.

## Next Steps

* [Quick Start](/docs/edge-compute/stateful-actors/quick-start) — ship the owner function this reference calls into
* [Runtime API](/docs/edge-compute/stateful-actors/api-reference) — `ActorNamespace`, `ActorStub`, and the binding surface
* [Alarms](/docs/edge-compute/stateful-actors/alarms) — schedule deferred work from inside an actor method
