Something went wrong

Thank you for being patient! We're working hard on resolving the issue

Row Identity - Lona Docs Log in

Row Identity

Three row identity types cover the three layers of the stack. Most app code only uses the first two, but knowing when to reach for each saves pain.

TypeLayerUse
RowKeyWire / serializedA stable, serializable row reference
RowLocalIdIn-memory sessionThe interned identity used by trees, maps, UI state
RowIdTyped API boundaryA generic-tagged interned id used at client APIs

All three live in @tento-lona/sheets and are re-exported from @tento-lona.

RowKey

Use RowKey when you need to parse, store, or pass around a stable reference to a row.

import { RowKey } from "@tento-lona/sheets";

const weather = RowKey.reserved("weather");
const revenue = RowKey.lookup("revenue");
const explicit = RowKey.parse("r_0123456789abcdef0123456789abcdef");

This is the right choice for:

  • configuration
  • saved references
  • programmatic row lookup
  • reserved/provider rows such as weather, calendar aggregates, or :~lona:tasks

RowKey is a pure value type — no interning, no session context, just the wire-format identifier as a parsed + validated object.

RowLocalId

Use RowLocalId when you are working with a row that is already loaded into the current app session. Reference equality is the key property:

const a = registry.resolveFromString("r_abc...");
const b = registry.resolveFromString("r_abc...");
a === b; // true — same object reference, safe as Map key

You will usually see RowLocalId values in:

  • sheet.tree()
  • invalidation events
  • UI state keyed by rows
  • Map<RowLocalId, T> and Set<RowLocalId>
const tree = sheet.tree();

for (const node of tree.nodes) {
  const row = sheet.row(node.id);
}

RowLocalId also supports aliasing — a row's canonical id (r_<hex>) and its lookup key (:revenue) resolve to the same RowLocalId instance once the sheet loads. This is what makes sheet.row({ lookupKey: ":x" }) and sheet.row(rowLocalId) interchangeable.

RowId

RowId is the third identity type — a generic-tagged interned id used at typed API boundaries. It appears in lower-level @tento-lona/sheets APIs where TypeScript needs to discriminate between user-backed rows, lookup rows, reserved rows, virtual rows, system rows, etc., at the type level.

import { RowId } from "@tento-lona/sheets";

const id: RowId = RowId.parse("r_0123456789abcdef0123456789abcdef");
if (id.isUser()) {
  const userId: RowId<"user"> = id.asUser();
}

Most application code never touches RowId directly — use RowKey at the wire boundary, convert to RowLocalId for the session. Reach for RowId only when working with internals that explicitly type a parameter as RowId<V>.

Resolving A Key

RowKey.resolve() converts a stable row reference into the in-memory identity for the current session:

const key = RowKey.lookup("revenue");
const localId = key.resolve();

That matters because a RowLocalId is reference-equal. If you use it as a Map key, resolving the same row again gives you the same in-memory key.

User-Scoped Keys

Not every row key is global.

  • UUID-backed rows are globally unique
  • lookup, virtual, and system keys are scoped to the current user

In most app code this is handled by LonaSdk.Client. If your application switches users in a long-lived client, call client.setCurrentUser(userId) before resolving user-scoped row keys.

Practical Rule

Use this rule of thumb:

  • use RowKey at boundaries (config, persistence, formulas)
  • use RowLocalId inside the running app (maps, trees, UI state)
  • use RowId only when a typed API explicitly asks for it

Package Layout

All three identity types are defined in @tento-lona/sheets:

import { RowKey, RowLocalId, RowId } from "@tento-lona/sheets";

The SDK (@tento-lona) re-exports them for convenience, so existing code that imports from @tento-lona continues to work. When writing new library-layer code, prefer the @tento-lona/sheets path — it's the canonical home.

See Also