# Builder.io Agent Native Best Practices: A Complete Implementation Guide

> Implement Builder.io Agent Native best practices. Use action surface as source of truth, persist state in SQL, route calls via provider-api-catalog, and ensure UI/agent use identical typed actions.

- Repository: [Builder.io/agent-native](https://github.com/BuilderIO/agent-native)
- Tags: best-practices
- Published: 2026-07-18

---

**The best way to use Builder.io Agent Native is to treat the action surface as your single source of truth, persist all state in SQL via Drizzle, route third-party calls through the provider-api-catalog, and ensure both UI and agent invoke identical typed actions defined with `defineAction`.**

Builder.io Agent Native tightly couples AI agents with UIs by having both invoke the same typed action surface. Following the architectural conventions defined in [`AGENTS.md`](https://github.com/BuilderIO/agent-native/blob/main/AGENTS.md) and implemented in the core source code ensures your applications remain secure, type-safe, and maintainable. This guide covers the essential patterns for defining actions, securing data, and implementing UI components according to the framework's four pillars: **Actions**, **Data**, **UI**, and **Agent Skills**.

## Core Architectural Principles

### Unify on the Action Surface

Define every mutating operation as a named action using `defineAction` from `@agent-native/core/actions` within the `actions/` directory. This creates a single source of truth that both your frontend and AI agent consume. The UI accesses these through `useActionQuery` and `useActionMutation` hooks, while agents invoke the same functions directly, ensuring behavioral parity across interfaces.

According to the [`AGENTS.md`](https://github.com/BuilderIO/agent-native/blob/main/AGENTS.md) Four-Area Checklist in the BuilderIO/agent-native repository, this unified surface prevents logic duplication and maintains type safety across the stack.

### Persist State in SQL via Drizzle

Store all persistent application state in **SQL** using Drizzle ORM. Reserve file or blob storage exclusively for large assets like images or documents, persisting only the resulting URLs or IDs in the database. This approach enables reliable transactions, consistent backups, and proper row-level security enforcement.

As documented in [`.agents/skills/storing-data/SKILL.md`](https://github.com/BuilderIO/agent-native/blob/main/.agents/skills/storing-data/SKILL.md), this pattern ensures data integrity and simplifies access control compared to distributed state management.

### Route External APIs Through the Provider Catalog

Access all third-party services through the **provider-api-catalog** (`@agent-native/core/provider-api`) rather than implementing custom REST wrappers. The catalog centralizes authentication, rate limiting, and request formatting for external services. Only bypass this catalog if the action surface lacks a required endpoint.

This convention is enforced in `packages/core/src/provider-api/` and detailed in [`.agents/skills/provider-api-catalog/SKILL.md`](https://github.com/BuilderIO/agent-native/blob/main/.agents/skills/provider-api-catalog/SKILL.md).

### Implement UI with Type-Safe Primitives

Build user interfaces using **TypeScript**, **shadcn/ui** primitives, and **Tabler Icons**. Implement optimistic updates for mutations to ensure responsive interfaces. Avoid imperative browser APIs such as `alert`, `prompt`, or raw `fetch` calls within UI code; all data fetching must route through the typed action hooks.

The frontend design standards in [`.agents/skills/frontend-design/SKILL.md`](https://github.com/BuilderIO/agent-native/blob/main/.agents/skills/frontend-design/SKILL.md) mandate this declarative approach to maintain consistency with the agent's capabilities.

### Enforce Security at Every Layer

Never embed secrets or credentials in source code. Store all sensitive configuration in `.env` files or your platform's secret store. Guard sensitive routes using `guard-no-env-credentials.mjs` and enforce access controls at the SQL level through `ownableColumns()` filters.

The security implementation in [`packages/core/src/extensions/routes.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/extensions/routes.ts) and documented in [`.agents/skills/security/SKILL.md`](https://github.com/BuilderIO/agent-native/blob/main/.agents/skills/security/SKILL.md) provides the regex parsers and guards necessary to block credential leaks before they reach production.

## Implementation Patterns

### Defining Strongly-Typed Actions

Create actions in the `actions/` directory using Zod schemas for input validation. The following example from the BuilderIO/agent-native source demonstrates the pattern:

```typescript
// actions/toggleFeature.ts
import { defineAction } from '@agent-native/core/actions';
import { z } from 'zod';

export const toggleFeature = defineAction({
  name: 'toggleFeature',
  input: z.object({
    featureId: z.string(),
    enable: z.boolean(),
  }),
  async handler({ input, ctx }) {
    // Secure SQL write respecting ownableColumns()
    await ctx.db
      .update(table.features)
      .set({ enabled: input.enable })
      .where(eq(table.features.id, input.featureId));
    
    return { success: true, featureId: input.featureId };
  },
});

```

### Consuming Actions in React Components

Import actions directly into your components and invoke them through `useActionMutation`. This ensures the UI uses the exact same logic and authorization checks as the agent:

```typescript
import { useActionMutation } from '@agent-native/core/hooks';
import { toggleFeature } from '@/actions/toggleFeature';

export function FeatureSwitch({ featureId }: { featureId: string }) {
  const { mutate, isLoading } = useActionMutation(toggleFeature);

  return (
    <Switch
      disabled={isLoading}
      onCheckedChange={(checked) =>
        mutate({ featureId, enable: checked })
      }
    />
  );
}

```

### Invoking Actions from Agent Skills

Agent skills should call the identical action surface used by the UI. Reference actions in skill documentation located in `.agents/skills/`:

```typescript
// .agents/skills/feature-toggle/SKILL.md (excerpt)
When a user wants to toggle a feature, use the `toggleFeature` action:

{
  "featureId": "checkout-promo",
  "enable": true
}

```

The agent will invoke `toggleFeature` exactly as the React component would, ensuring consistent business logic.

### Accessing Third-Party Services

Use `callProvider` from the provider-api-catalog to interact with external APIs:

```typescript
import { callProvider } from '@agent-native/core/provider-api';

const result = await callProvider('stripe', {
  method: 'POST',
  path: '/v1/customers',
  body: { email: user.email },
});

```

## Extension Development

### Building Sandboxed SQL-Backed Extensions

Develop sandboxed mini-applications as **SQL-backed extensions** that interact with the main app via `appAction`, `dbQuery`, and `extensionFetch`. This architecture prevents logic duplication and maintains isolation between extensions.

As detailed in [`.agents/skills/extensions/SKILL.md`](https://github.com/BuilderIO/agent-native/blob/main/.agents/skills/extensions/SKILL.md), extensions should leverage the database for state management rather than maintaining independent storage systems.

## Testing and Validation

### Running QA Scripts and Guards

Execute the provided smoke test suite after every change to verify action integrity and security posture. The `scripts/qa-*.ts` files, including [`qa-public-share-smoke.ts`](https://github.com/BuilderIO/agent-native/blob/main/qa-public-share-smoke.ts), validate that guards still block disallowed patterns and that actions behave correctly under various permission contexts.

Add unit tests for new actions to ensure handler logic respects row-level security and input validation schemas.

## Summary

- **Treat the action surface as canonical**: Define all operations in `actions/` using `defineAction` and consume them via `useActionMutation` or direct agent invocation.
- **Persist data in SQL**: Use Drizzle ORM for state management; limit blob storage to asset URLs.
- **Centralize external APIs**: Route all third-party calls through `@agent-native/core/provider-api`.
- **Security hardening**: Keep credentials in `.env`, guard routes with `guard-no-env-credentials.mjs`, and enforce SQL-level filters.
- **Agent prompt engineering**: Follow the Claude/Anthropic best-practice guidelines from [`CHANGELOG.md`](https://github.com/BuilderIO/agent-native/blob/main/CHANGELOG.md) version 6.4.38 by keeping prompts concise and including verification steps.

## Frequently Asked Questions

### How do I share logic between the UI and agent in Agent Native?

Define the logic once using `defineAction` in the `actions/` directory and import it into both your React components (via `useActionMutation`) and your agent skills. This ensures both interfaces execute identical code paths with the same validation and security checks.

### Where should I store API secrets in a Builder.io Agent Native app?

Store all secrets in `.env` files or your hosting platform's secret management system. Never commit credentials to source control. Use `guard-no-env-credentials.mjs` to programmatically validate that sensitive data does not leak into client bundles or logs.

### Can I use raw fetch calls for external APIs?

No. Instead of raw `fetch`, use `callProvider` from `@agent-native/core/provider-api`. The provider catalog handles authentication, base URLs, and error formatting consistently across the application, whereas raw fetch calls bypass these security and standardization layers.

### What testing strategy does Agent Native recommend?

Run the provided QA scripts in `scripts/qa-*.ts` after each deployment to smoke-test actions and security guards. Additionally, write unit tests for individual action handlers to verify they respect database filters and Zod input schemas, particularly for mutations affecting sensitive data.