# What Is the `application_state` Table in Agent-Native?

> Explore the application_state table in Agent-Native. Discover how this SQL-backed store manages transient UI and navigation data for seamless agent and frontend component interaction.

- Repository: [Builder.io/agent-native](https://github.com/BuilderIO/agent-native)
- Tags: deep-dive
- Published: 2026-06-28

---

**The `application_state` table is a session-scoped, SQL-backed key-value store that persists transient UI and navigation data for agents and front-end components in the BuilderIO/agent-native framework.**

The `application_state` table serves as the central coordination mechanism in Agent-Native, enabling seamless state synchronization between AI agents and user interfaces. Unlike permanent user data models, this table stores ephemeral information such as form drafts, navigation commands, and refresh flags that survive page reloads but remain strictly isolated to specific user sessions.

## Architecture and Design

The `application_state` table acts as a shared, persistent context layer that bridges the gap between server-side agent logic and client-side UI components. It ensures that short-lived state survives browser refreshes while maintaining strict data isolation between concurrent users.

### Ephemeral Data Storage

Each row in the `application_state` table stores transient data that agents and UIs need to access without polluting the permanent data model. Common use cases include:

- Draft content and form selections
- Navigation commands and URL synchronization data
- Refresh-screen flags and UI update triggers
- Temporary agent context that must persist across tool calls

### Session-Scoped Isolation

The table implements strict session scoping through a `session_id` column. This design ensures that concurrent users or multiple agents operating simultaneously never clash over shared keys. According to the scoping configuration in [`packages/core/src/scripts/db/scoping.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/scripts/db/scoping.ts), the table is declared as an exact-match scoped table, meaning all queries are automatically filtered to the current user and organization context.

### Database Schema

The table schema follows a simple key-value structure managed by Drizzle:

- `session_id` – Identifies the user session for isolation
- `key` – String identifier for the state entry (e.g., `draft:post`, `navigation:command`)
- `value` – JSON-serialized data payload
- `updated_at` – Timestamp for tracking modifications

The migration script in [`scripts/qa-public-share-smoke.ts`](https://github.com/BuilderIO/agent-native/blob/main/scripts/qa-public-share-smoke.ts) ensures the table exists on fresh databases by executing `CREATE TABLE IF NOT EXISTS application_state (...)`.

## Client API Implementation

Front-end applications interact with the `application_state` table through a typed client API located in [`packages/core/src/client/application-state.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/client/application-state.ts). This layer handles HTTP communication, JSON serialization, and request validation.

The client functions communicate with the internal route `/_agent-native/application-state/:key`, providing a RESTful interface for state management.

### Reading State Values

Use `readClientAppState` to retrieve typed data from the table:

```typescript
import { readClientAppState } from '@agent-native/core/client';

async function getDraft() {
  const draft = await readClientAppState<{ title: string; body: string }>(
    'draft:post',
  );
  console.log('Current draft:', draft);
}

```

This executes a `GET` request to `/_agent-native/application-state/draft:post` and returns the stored JSON or `null` if the key does not exist.

### Writing State Values

Use `writeClientAppState` to persist data with optional metadata:

```typescript
import { writeClientAppState } from '@agent-native/core/client';

async function saveDraft(data: { title: string; body: string }) {
  await writeClientAppState('draft:post', data, {
    requestSource: 'ui',
  });
}

```

Internally, this performs a `PUT` request with `Content-Type: application/json`. The `requestSource` parameter enables audit logging by tagging the origin of the write operation.

### Deleting State Keys

Use `setClientAppState` with `undefined` or `null` to remove entries:

```typescript
import { setClientAppState } from '@agent-native/core/client';

async function clearDraft() {
  await setClientAppState('draft:post', undefined); // deletes the row
}

```

The `deleteClientAppState` function provides an explicit alternative for removal operations.

## Server-Side Integration

The server implementation treats `application_state` as both an observation target and a read-only data source for agent tools.

### Polling and UI Synchronization

The polling system in [`packages/core/src/server/poll.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/server/poll.ts) actively monitors the `application_state` table for changes to specific keys like `refresh-screen` and `set-url`. When detected, the server broadcasts updates to connected front-end clients, enabling real-time UI synchronization without requiring full page reloads or action-layer round trips.

### Database Tool Access

Server-side tools can query the table using the `db-query` tool, though writes should route through the client API to maintain scoping and audit consistency:

```typescript
import { dbQuery } from '@agent-native/core/server';

async function getAllNavCommands(sessionId: string) {
  const rows = await dbQuery(
    `SELECT key, value FROM application_state WHERE session_id = $1`,
    [sessionId],
  );
  return rows;
}

```

The framework documentation in [`packages/core/src/server/prompts/framework-core.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/server/prompts/framework-core.ts) instructs LLM agents to use specific `readAppState` and `writeAppState` tools rather than direct SQL manipulation, ensuring proper access patterns.

## Key Source Files

| Area | File | Purpose |
|------|------|---------|
| **Client API** | [`packages/core/src/client/application-state.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/client/application-state.ts) | Typed functions (`readClientAppState`, `writeClientAppState`, `setClientAppState`, `deleteClientAppState`) for front-end state management |
| **Server Polling** | [`packages/core/src/server/poll.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/server/poll.ts) | Watches table changes and pushes real-time updates to the UI |
| **Database Schema** | [`scripts/qa-public-share-smoke.ts`](https://github.com/BuilderIO/agent-native/blob/main/scripts/qa-public-share-smoke.ts) | Contains `CREATE TABLE IF NOT EXISTS application_state` migration logic |
| **Scoping Configuration** | [`packages/core/src/scripts/db/scoping.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/scripts/db/scoping.ts) | Declares `application_state` as a session-scoped table with `session_id` column filtering |
| **Agent Documentation** | [`packages/core/src/server/prompts/framework-core.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/server/prompts/framework-core.ts) | Explains LLM tool usage for `application_state` interactions |

## Summary

- The `application_state` table provides a **session-scoped, SQL-backed key-value store** for transient UI and agent data in Agent-Native.
- Data is automatically isolated by `session_id` and scoped to the current user organization, preventing cross-session contamination.
- Front-end applications use the **client API** in [`application-state.ts`](https://github.com/BuilderIO/agent-native/blob/main/application-state.ts) to read, write, and delete values via HTTP requests to `/_agent-native/application-state/:key`.
- The **server polling mechanism** monitors the table for navigation and refresh commands, pushing real-time updates to connected clients.
- While server tools can query the table via `db-query`, writes should use the typed client API to preserve scoping rules and audit trails.

## Frequently Asked Questions

### What types of data should be stored in the `application_state` table?

Store only ephemeral, UI-specific data such as form drafts, navigation commands, refresh flags, and temporary agent context. Do not use this table for permanent user data or business-critical information that requires long-term persistence, as it is designed for short-lived state that can be safely discarded after the session ends.

### How does Agent-Native prevent session collisions in the `application_state` table?

The table uses a `session_id` column combined with automatic scoping logic defined in [`packages/core/src/scripts/db/scoping.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/scripts/db/scoping.ts). Every query is filtered to the current session, ensuring that users or agents operating in different sessions cannot read or overwrite each other's state entries even if they use identical keys.

### Can agents write directly to the `application_state` table using SQL tools?

While agents can read from the table using the `db-query` tool, direct SQL writes are discouraged. The framework provides specific `writeAppState` and `setClientAppState` tools that route through the HTTP API, ensuring proper JSON serialization, audit logging via `requestSource` headers, and enforcement of scoping rules that raw SQL might bypass.

### Where is the `application_state` table schema defined in the source code?

The schema is defined in the migration script located at [`scripts/qa-public-share-smoke.ts`](https://github.com/BuilderIO/agent-native/blob/main/scripts/qa-public-share-smoke.ts), which executes `CREATE TABLE IF NOT EXISTS application_state (session_id, key, value, updated_at)`. Additionally, the scoping configuration in [`packages/core/src/scripts/db/scoping.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/scripts/db/scoping.ts) registers the table as an exact-match scoped entity within the Drizzle ORM configuration.