# Actor Keys > Source: `src/content/docs/actors/keys.mdx` > Canonical URL: https://rivet.dev/docs/actors/keys > Description: Actor keys uniquely identify actor instances within each actor type. Keys are used for addressing which specific actor to communicate with. --- ## Key Format Actor keys can be either a string or an array of strings: ```typescript import { actor, setup } from "rivetkit"; import { createClient } from "rivetkit/client"; const counter = actor({ state: { count: 0 }, actions: { increment: (c) => c.state.count++ } }); const chatRoom = actor({ state: { messages: [] as string[] }, actions: {} }); const registry = setup({ use: { counter, chatRoom } }); const client = createClient("http://localhost:6420"); // String key const counterHandle = client.counter.getOrCreate(["my-counter"]); // Array key (compound key) const chatRoomHandle = client.chatRoom.getOrCreate(["room", "general"]); ``` ### Compound Keys & User Data Array keys are useful when you need compound keys with user-provided data. Using arrays makes adding user data safe by preventing key injection attacks: ```typescript import { actor, setup } from "rivetkit"; import { createClient } from "rivetkit/client"; const chatRoom = actor({ state: { messages: [] as string[] }, actions: {} }); const gameRoom = actor({ state: { players: [] as string[] }, actions: {} }); const workspace = actor({ state: { data: {} }, actions: {} }); const registry = setup({ use: { chatRoom, gameRoom, workspace } }); const client = createClient("http://localhost:6420"); // Example user data const userId = "user-123"; const gameId = "game-456"; const tenantId = "tenant-789"; const workspaceId = "workspace-abc"; // User-specific chat rooms const userRoomHandle = client.chatRoom.getOrCreate(["user", userId, "private"]); // Game rooms by region and difficulty const gameRoomHandle = client.gameRoom.getOrCreate(["us-west", "hard", gameId]); // Multi-tenant resources const workspaceHandle = client.workspace.getOrCreate(["tenant", tenantId, workspaceId]); ``` This allows you to create hierarchical addressing schemes and organize actors by multiple dimensions. Don't build keys using string interpolation like `"foo:${userId}:bar"` when `userId` contains user data. If a user provides a value containing the delimiter (`:` in this example), it can break your key structure and cause key injection attacks. ### Omitting Keys You can create actors without specifying a key in situations where there is a singleton actor (i.e. only one actor of a given type). For example: ```typescript import { actor, setup } from "rivetkit"; import { createClient } from "rivetkit/client"; const globalActor = actor({ state: { config: {} }, actions: {} }); const registry = setup({ use: { globalActor } }); const client = createClient("http://localhost:6420"); // Get the singleton session const globalActorHandle = client.globalActor.getOrCreate(); ``` This pattern should be avoided, since a singleton actor usually means you have a single actor serving all traffic & your application will not scale. See [scaling documentation](/docs/actors/scaling) for more information. ### Key Uniqueness Keys are unique within each actor name. Different actor types can use the same key: ```typescript import { actor, setup } from "rivetkit"; import { createClient } from "rivetkit/client"; const chatRoom = actor({ state: { messages: [] as string[] }, actions: {} }); const userProfile = actor({ state: { name: "" }, actions: {} }); const registry = setup({ use: { chatRoom, userProfile } }); const client = createClient("http://localhost:6420"); // These are different actors, same key is fine const userChat = client.chatRoom.getOrCreate(["user-123"]); const userProfileHandle = client.userProfile.getOrCreate(["user-123"]); ``` ## Accessing Keys in Metadata Access the actor's key within the actor using the [metadata](/docs/actors/metadata) API: ```typescript index.ts import { actor, setup } from "rivetkit"; const chatRoom = actor({ state: { messages: [] as string[] }, actions: { getRoomName: (c) => { // Access the key from metadata const key = c.key; return key[1]; // Get "general" from ["room", "general"] } } }); export const registry = setup({ use: { chatRoom } }); ``` ```typescript client.ts import { actor, setup } from "rivetkit"; import { createClient } from "rivetkit/client"; const chatRoom = actor({ state: { messages: [] as string[] }, actions: { getRoomName: (c) => c.key[1] } }); const registry = setup({ use: { chatRoom } }); const client = createClient("http://localhost:6420"); async function connectToRoom(roomName: string) { // Connect to a chat room const chatRoomHandle = client.chatRoom.getOrCreate(["room", roomName]); // Get the room name from the key const retrievedRoomName = await chatRoomHandle.getRoomName(); console.log("Room name:", retrievedRoomName); // e.g., "general" return chatRoomHandle; } // Usage example const generalRoom = await connectToRoom("general"); ``` ## Configuration Examples ### Simple Configuration with Keys Use keys to provide basic actor configuration: ```typescript index.ts import { actor, setup } from "rivetkit"; interface UserSessionState { userId: string; loginTime: number; preferences: Record; } const userSession = actor({ createState: (c): UserSessionState => ({ userId: c.key[0], // Extract user ID from key loginTime: Date.now(), preferences: {} }), actions: { getUserId: (c) => c.state.userId } }); export const registry = setup({ use: { userSession } }); ``` ```typescript client.ts import { actor, setup } from "rivetkit"; import { createClient } from "rivetkit/client"; const userSession = actor({ state: { userId: "", loginTime: 0, preferences: {} }, actions: { getUserId: (c) => c.state.userId } }); const registry = setup({ use: { userSession } }); const client = createClient("http://localhost:6420"); // Pass user ID in the key for user-specific actors const userId = "user-123"; const userSessionHandle = client.userSession.getOrCreate([userId]); ``` ### Complex Configuration with Input For more complex configuration, use [input parameters](/docs/actors/input): ```typescript client.ts import { actor, setup } from "rivetkit"; import { createClient } from "rivetkit/client"; interface ChatRoomInput { maxUsers: number; isPrivate: boolean; moderators: string[]; settings: { allowImages: boolean; slowMode: boolean }; } const chatRoom = actor({ createState: (c, input: ChatRoomInput) => ({ maxUsers: input.maxUsers, isPrivate: input.isPrivate, moderators: input.moderators, settings: input.settings, }), actions: {} }); const registry = setup({ use: { chatRoom } }); const client = createClient("http://localhost:6420"); const roomName = "general"; // Create with both key and input const chatRoomHandle = await client.chatRoom.create(["room", roomName], { input: { maxUsers: 100, isPrivate: false, moderators: ["admin1", "admin2"], settings: { allowImages: true, slowMode: false } } }); ``` ## API Reference - [`ActorKey`](/typedoc/types/rivetkit.mod.ActorKey.html) - Key type for actors - [`ActorQuery`](/typedoc/types/rivetkit.mod.ActorQuery.html) - Query type using keys - [`GetOptions`](/typedoc/interfaces/rivetkit.client_mod.GetOptions.html) - Options for getting by key - [`QueryOptions`](/typedoc/interfaces/rivetkit.client_mod.QueryOptions.html) - Options for querying _Source doc path: /docs/actors/keys_