Skip to content

← Blog#ai-agents

A2UI 1.0 in Next.js: The Deep Dive and Your First Agent Screen

A2UI 1.0 lets agents answer with screens instead of text. I built a real surface in Next.js with Google's renderer: the spec, the security model, the verdict.

Muhammad Zain Ul Abidin20 min read
On this page
Your agent's worst answers are not wrong. They are shaped wrong. Ask it to compare three flights, approve a deploy, or collect six fields, and it hands you a paragraph - then three rounds of "which one?" while the decision dissolves into chat history. Google's answer to that shape problem is A2UI, an open protocol where the agent describes a screen as JSON and your app renders it with its own components. Version 1.0 went stable on November 11, 2026. I did not stop at the announcement: I installed Google's React renderer, fed it a real 1.0 payload in a Next.js app, clicked the buttons, and read the spec end to end. This is what I found - the protocol's anatomy, its security model, the places it is still held together with tape, and whether you should build on it.

The short version: the agent describes, your app draws

A2UI splits one job into two. The agent decides what the user needs to see and sends a stream of JSON messages naming components from a catalog - a card, a text line, a choice picker, a button - plus the data those components bind to. Your application owns everything visual: it renders each named component with its own native implementation, in its own design system, at native speed. The agent never sends HTML, never sends code, and cannot invent a component you did not register.

Three consequences follow from that split, and they are the whole pitch. First, one agent answer renders everywhere the catalog exists - web, Android, iOS, or inside an assistant like Claude or Gemini that hosts agent UI. Second, the trust boundary is structural: the worst a bad payload can do is arrange your own components badly. Third, styling is entirely yours, because the protocol carries no theme at all - a 1.0 message that tries to set one is invalid.

You do not have to take the shape on faith. The playground below is the protocol in miniature: compose a surface, watch the payload rebuild itself, and press the rendered buttons to see the action messages an agent receives back.

Why agents answering in text breaks down

Text is a fine medium for answers that are prose. It is a poor medium for answers that are decisions. Comparing three products in a paragraph forces the reader to hold the comparison table in their head. Approving a plan in chat means the plan's details scroll away while the approval stays ambiguous. Collecting structured input through conversation turns one form into six round trips, each one a chance to abandon the task.

Google's framing is that agent interaction today sits where computing sat in the terminal era: capable, and answering almost everything in text. The interesting part is not the analogy, it is which tasks break first. In my own work building agents, the failures cluster in exactly three shapes:

  • Approvals. A deploy, a payment, a change to a record. The user must see precisely what will happen and confirm it. Text buries the specifics and makes "yes" ambiguous - yes to what, exactly, at which values?
  • Comparisons and pickers. Flights, plans, products, time slots. The information is inherently tabular and the action is a selection. A list in prose makes the user do the layout work the interface should do.
  • Forms. Any time the agent needs five fields, chat becomes a slow, error-prone form with no validation until the end.

Notice what these three have in common: the set of screens is small and known in advance, even though the data changes every time. That is the exact workload a component catalog fits. A2UI is not trying to let agents design arbitrary interfaces. It is giving them a safe way to fill in the screens your product already knows it needs, with data only the agent has.

The protocol: four messages, one data model

An A2UI conversation is a stream of JSON objects from agent to renderer. Four message types do the structural work, and every one of them is small enough to hold in your head.

  • createSurface opens a named surface - a region of UI the agent owns - and in 1.0 it can carry the full component list and the initial data model inline, so a complete screen arrives in a single message.
  • updateComponents adds or replaces component definitions on a surface.
  • updateDataModel replaces the data at a JSON Pointer path, so the agent can change what the screen shows without resending the screen.
  • deleteSurface tears a surface down.

Components arrive as a flat list, not a nested tree. Each component has an id, a component name from the catalog, and properties; containers reference their children by id, in what the spec calls an adjacency list. One component must carry the id root - it mounts under the surface's implicit container. Here is a complete, valid 1.0 payload, the same shape as the deploy approval I rendered in my test build:

json
{
  "version": "1.0",
  "createSurface": {
    "surfaceId": "deploy-confirm",
    "catalogId": "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json",
    "sendDataModel": true,
    "components": [
      { "id": "root", "component": "Card", "child": "col" },
      { "id": "col", "component": "Column", "children": ["title", "picker", "go"] },
      { "id": "title", "component": "Text", "text": "Deploy to production?" },
      {
        "id": "picker",
        "component": "ChoicePicker",
        "variant": "mutuallyExclusive",
        "options": [
          { "label": "Production", "value": "production" },
          { "label": "Preview", "value": "preview" }
        ],
        "value": { "@path": "/environment" }
      },
      {
        "id": "go",
        "component": "Button",
        "variant": "primary",
        "child": "goLabel",
        "action": {
          "event": {
            "name": "confirm_deploy",
            "context": { "environment": { "@path": "/environment" } }
          }
        }
      },
      { "id": "goLabel", "component": "Text", "text": "Confirm deploy" }
    ],
    "dataModel": { "environment": "production" }
  }
}

The catalog named in catalogId is the vocabulary contract. The basic catalog that ships with the spec has 18 components: layout (Row, Column, List, Card, Tabs, Divider, Modal), display (Text, Image, Icon, Video, AudioPlayer), and input (Button, CheckBox, TextField, DateTimeInput, ChoicePicker, Slider). You are not stuck with it. A catalog is just a schema document, and defining your own - your design system's components, with your prop shapes - is the intended production move. The agent generates against whichever catalog you put in its prompt.

Two design choices in this anatomy matter more than they look. The flat adjacency list means an agent can stream components in any order and patch one component without resending the tree - partial updates are cheap. And the hard split between component structure and data model means the data can move on its own channel of updates: a live price, a typing user, and an agent patch all write to the same model the components read from.

The return trip has its own message family. When a user presses a button, the renderer sends an action message: the action's name plus a context object whose values are resolved from the data model at press time. Version 1.0 adds explicit function-call messages in both directions - callAgentFunction when the UI needs the agent to check something mid-interaction (the spec's example is a flight picker verifying availability on the spot), and callRendererFunction when the agent needs something only the client knows. Those two turn a mostly one-way description protocol into a conversation, and they are the headline feature of 1.0.

The protocol is deliberately transport-agnostic. The spec defines bindings for AG-UI (the standard one for agent frontends), an A2A extension for agent-to-agent traffic, MCP tool calls and outputs, and plain SSE or WebSockets. The transport contract is three things: messages arrive in order, messages are framed as discrete JSON objects, and metadata can ride along - the renderer uses it to send the current data model back with actions when a surface sets sendDataModel, and to exchange capability information about which catalogs each side supports.

Data binding: @path, @call, and a two-way street

A component property in A2UI is rarely a plain value. The spec calls the bindable types Dynamic types, and each accepts three forms: a literal, a data binding written {"@path": "/user/name"} using JSON Pointer syntax, or a function call written {"@call": "formatCurrency", "args": {...}}. The @ namespace is reserved for the protocol - @path, @call, and a system function @index that returns the position of the current item when a list template renders.

The function set in the basic catalog tells you what the protocol expects to happen on the client. Formatting functions (formatString, formatNumber, formatCurrency, formatDate, pluralize) turn raw model values into display text locally, so the agent ships numbers, not pre-formatted strings. formatString supports interpolation - "Build ${/build/id} from commit ${/build/commit}" is a binding, and in my test build it resolved against the data model exactly as written. Validation functions (required, email, regex, length, numeric) power @checks: declarative validation rules attached to inputs and buttons, evaluated by the renderer, with error messages the component displays. The regex function even runs a static safety check on patterns first, rejecting the shapes that cause catastrophic backtracking. Someone on this spec has been hurt by regex denial-of-service before, and it shows in a good way.

Binding runs both ways. The input components - TextField, CheckBox, Slider, ChoicePicker, DateTimeInput - write user input back into the data model at their bound path. Bind a Text label to the same path and it updates live as the user types. That two-way binding is what makes an A2UI surface feel like an app instead of a screenshot: the data model is shared state, the agent reads the final state through the action context or the sendDataModel metadata, and nobody re-parses prose to find out what the user typed.

Lists get a template mechanism instead of repetition. A container's children can be a template: one component id plus a path to an array in the data model. The renderer stamps the template once per item, bindings inside resolve relative to that item, and ${@index()} gives you numbering. An agent returning forty search results describes one row, not forty - which matters, because the agent is paying for every token of payload it writes.

The security model: the catalog is the permission slip

The standard the project sets for itself is "safe like data, expressive like code", and the mechanism is genuinely simple. The agent's output is data - JSON describing components. It is never code, never markup, and the renderer only knows how to draw components from catalogs it registered. A prompt-injected agent, or a compromised one, cannot smuggle in a script tag, an iframe, or a component you did not build. Its entire vocabulary of harm is rearranging your own components.

The function rules tighten this further. Every catalog function declares who may call it: the renderer only, the agent only, or both. Functions that require a real user gesture - openUrl is the spec's example - must be declared renderer-only, and if an agent tries to invoke one through callRendererFunction, the renderer rejects it with a structured error. Sensitive data gets a matching protection on the server side: Google points out that binding can happen server-side, so the values a component displays never have to pass through the model at all. The agent can say "put the account balance here" without ever seeing the balance.

Now the part the launch posts skip. This model constrains components, not intent. An agent that wants to deceive your user can compose a perfectly legal surface from your catalog: a card that looks like a confirmation but confirms something else, a primary button labeled for the safe action wired to the destructive one. A2UI gives you no protection there, and it cannot - the same is true of any UI your own frontend team ships. The correct mental model is that A2UI makes agent output exactly as trustworthy as your own UI code, no more and no less. Two practices follow. Treat action handlers as API endpoints: authorize them server-side, every time, because the action name and context are client-supplied data. And validate payloads before rendering, against the catalog schema, so malformed or off-catalog output dies at the boundary - the spec even defines the error format for feeding validation failures back to the model so it can correct itself.

One more boundary worth naming: the agent learns whatever the user types into bound fields when the action fires. If a surface collects something sensitive, that is a data-flow decision you made in the catalog and the surface design, not a protocol leak. Design surfaces like you design forms, because that is what they are.

Streaming: the screen assembles in order

A2UI was designed for a model that is still thinking. Messages arrive as a stream, the renderer applies them in order, and the interface builds progressively: the spec tells renderers to draw placeholders for components whose children or data have not arrived yet, rather than waiting for a complete payload. A slow agent does not mean a blank panel - it means a screen that assembles itself, section by section, and fills in as bindings resolve.

Three properties make this work in practice. The stream is stateful and ordered, which is why the transport contract demands reliable in-order delivery: a updateDataModel that lands before its createSurface is a corrupt stream, not a race you can shrug off. Updates are granular - one component definition or one data path per message - so a live-updating screen costs a trickle of small JSON objects, not full re-renders of the payload. And the end of the agent's turn is the transport's business, not a protocol message, which keeps the protocol usable over everything from server-sent events to A2A.

The practical consequence for your frontend: perceived latency is a property of how early the first useful message arrives, and that is under the agent's control, not the protocol's. An agent that sends the surface skeleton first and streams data patches after will feel fast. One that composes the entire payload before sending anything will feel exactly as slow as the text it replaced. If you adopt A2UI, prompt and structure your agent for skeleton-first streaming from day one; retrofitting it is miserable.

A2UI vs AG-UI vs MCP Apps vs hand-rolled JSON

These four get compared as if they were rivals. Two of them are not even the same kind of thing, and untangling that is worth more than any feature matrix.

AG-UI is the event protocol between an agent backend and a frontend: how messages, tool calls, state patches and UI payloads travel, with SDKs across the agent frameworks. It is a transport and interaction layer. A2UI payloads are one of the things it carries. Choosing AG-UI does not answer "what does the agent's UI look like" - A2UI is one possible answer to that question, riding on AG-UI's pipe.

MCP Apps is the opposite rendering philosophy. An MCP server registers an HTML resource under a ui:// URI, a tool points at it, and the host renders that HTML in a sandboxed iframe. The server ships real interface code; the host's job is containment. That buys total layout freedom - it is just a web page - at the cost of your design system, native feel, and any rendering outside a web view. A2UI ships a description; the host's own components do the drawing. Notably, they compose: Google documents running A2UI screens inside MCP Apps hosts, which is how Alation shows its feeds inside Claude.

Hand-rolled JSON is what most of us actually have: the agent emits structured output, our frontend maps it to components we wrote. It works, it is fully ours, and it quietly becomes a private protocol - undocumented schema, no validation, no second renderer, and a rewrite waiting for the day the same agent needs a mobile app. I say this as someone who has built agents on a hand-rolled harness and defends the approach: the harness is not the problem, but an unversioned UI dialect of your own invention becomes one.

A2UIAG-UIMCP AppsHand-rolled JSON
What it isA UI description formatAn agent-frontend event protocolA way to ship HTML UI from an MCP serverYour own structured output
What travelsJSON component descriptions + dataEvents: messages, state, tool calls, UI payloadsAn HTML resource rendered by the hostWhatever JSON you invented
Who rendersThe host app, with its own componentsN/A - it is the pipe, not the pictureThe server's HTML, in a sandboxed iframeYour frontend, by hand
Design systemYours, exactlyN/AThe server's, not the host'sYours, exactly
Cross-platformSame payload on web, Android, iOSWherever its SDKs runWeb-view hosts onlyOne frontend at a time
Main riskYoung spec, renderer maturityNone for A2UI - they composeIframe UX and host support varianceBecoming an unversioned private protocol

The decision this table supports: if your agent lives inside your own product, A2UI and hand-rolled JSON are the real contenders, and the question is whether you want a spec, a validator and a second renderer someday, or full control and full maintenance. If your agent must appear inside other people's assistants, you are in MCP territory - and A2UI can ride inside it. AG-UI enters the picture when you want a standard pipe between your agent and any of the above.

The ecosystem: who ships what

Everything below is open source under Apache-2.0. There is nothing to buy, which is worth stating plainly in a landscape where agent tooling usually has a pricing page.

PieceWhat exists todaySource
SpecA2UI 1.0, current since the Nov 11, 2026 release; 0.9.1 previous, 0.8 deprecateda2ui.org
Web renderersReact, Angular, Lit (@a2ui/react, @a2ui/web_core at 0.15.0)npm
Mobile renderersFlutter, SwiftUI at 1.0; Jetpack Compose at 0.9.1, 1.0 cominga2ui.org
Agent SDKsPython, TypeScript, Dart - generation help, message translation, error correctionGoogle announcement
TransportsAG-UI, A2A extension, MCP binding, SSE, WebSocketsSpec
Generation aidsA2UI Express format, Python macros, decision models (ByteDance's Jev) instead of LLM-written JSONGoogle announcement
Hosts and adoptersAtlassian (Jira), Alation, Bloomberg, ByteDance (Lynx renderer); Gemini renders 0.9.1 todayGoogle announcement

Your first A2UI screen in Next.js, from a build that actually runs

Enough spec. I built the smallest honest version of this: a Next.js 16 app where an agent's answer is a deploy-confirmation card, rendered by Google's official React renderer from one 1.0 message, with the button press coming back as an action. Everything in this section is from that build - the code ran, the typecheck passed, and I clicked the result in a browser before writing a word of it.

  1. Install the renderer and the core

    bash
    npm install @a2ui/react @a2ui/web_core

    Two packages: the React renderer and the framework-agnostic core that parses messages and holds surface state. As of this writing both are at 0.15.0 - the spec is 1.0, the packages are not, and that gap will matter again in the limits section. Pin exact versions.

  2. Load the surface client-only

    The renderer registers custom elements the moment it loads, so importing it in a server component kills your build at prerender with ReferenceError: HTMLElement is not defined. I hit this on the first build. The fix is the standard Next.js shape: wrap the surface component in next/dynamic with ssr: false, inside a small client component.

    tsx
    "use client";
    
    import dynamic from "next/dynamic";
    
    // The A2UI React renderer registers custom elements when it loads, so it
    // cannot be imported on the server at all. Load the surface client-only.
    export const AgentScreen = dynamic(
      () => import("./AgentScreen").then((m) => m.AgentScreen),
      { ssr: false, loading: () => <p>Waiting for the agent...</p> },
    );
  3. Create the processor and feed it the payload

    The MessageProcessor from @a2ui/web_core/v1_0 owns the protocol state: give it your catalogs and an action handler, feed it messages, render the surfaces it builds. One gotcha lives here - name the generic. Without the explicit type argument on the processor, TypeScript infers a surface type that A2uiSurface refuses, and the error gives you no hint that a type argument was the fix.

    tsx
    "use client";
    
    import { useEffect, useState } from "react";
    import { A2uiSurface, type ReactCatalogComponent } from "@a2ui/react";
    import { MessageProcessor, basicCatalog } from "@a2ui/web_core/v1_0";
    import { agentMessages } from "./agentMessages";
    
    export function AgentScreen() {
      const [lastAction, setLastAction] = useState<unknown>(null);
    
      const [processor] = useState(() => {
        const p = new MessageProcessor<ReactCatalogComponent>(
          [basicCatalog],
          (action) => {
            // The renderer-to-agent return channel. In production this goes
            // back over your transport; here we keep it where we can see it.
            setLastAction({ name: action.name, context: action.context });
          },
        );
        p.processMessages(agentMessages);
        return p;
      });
    
      const [surfaces, setSurfaces] = useState(() =>
        Array.from(processor.model.surfacesMap.values()),
      );
    
      useEffect(() => {
        const sync = () =>
          setSurfaces(Array.from(processor.model.surfacesMap.values()));
        const created = processor.onSurfaceCreated(sync);
        const deleted = processor.onSurfaceDeleted(sync);
        return () => {
          created.unsubscribe();
          deleted.unsubscribe();
        };
      }, [processor]);
    
      return (
        <div>
          {surfaces.map((surface) => (
            <A2uiSurface key={surface.id} surface={surface} />
          ))}
        </div>
      );
    }

    The payload itself - agentMessages - is the deploy card from the protocol section, extended with a data-bound summary line, an environment picker, and a release-note field. In a real app those messages arrive from your agent over SSE or AG-UI; where they come from is the one part of this architecture the protocol refuses to care about. If your agent runs on the Vercel AI SDK or a hand-written loop - the choice I weighed in framework vs harness - it emits the same JSON either way. The TypeScript agent SDK exists to help with generation and validation, but the wire format is the contract, not the SDK.

  4. Press the button and read what comes back

    Rendered, the card shows the interpolated summary ("Build dpl_8f3ka from commit 5037730. 214 tests passing, 0 failing."), the environment radios, and the note field - none of it written as JSX by me. I selected Preview, typed a note, and clicked Confirm deploy. The action handler received exactly this:

    json
    {
      "name": "confirm_deploy",
      "context": {
        "environment": ["preview"],
        "note": "Ship the A2UI deep dive"
      }
    }

    Two observations from that output. The round trip works precisely as the spec describes - context values resolved from the data model at press time, no prose to parse. And a real quirk: the ChoicePicker reports its selection as an array even in mutuallyExclusive mode. Harmless, but it is the kind of detail you want to learn from a test build rather than from a production bug report, and your agent's action handler has to expect it.

That is the entire integration: one client-only component, one processor, one payload, one action handler. The setup steps, in the checklist form I now keep for this:

What 1.0 does not give you yet

A deep dive that skips this section is a launch post with extra steps. Here is what I would want to know before betting a roadmap on A2UI, stated as plainly as the evidence allows.

The spec is 1.0; the software is 0.15. The renderer and core packages sit at 0.15.0, and the three releases before that each changed how 1.0 payloads are read. The React package's own entry points still carry the previous version's naming. None of this is damning - it is what a healthy young ecosystem looks like - but it means upgrades are events you schedule and test, not bumps you merge on a Friday.

Platform coverage is uneven. Jetpack Compose renders protocol 0.9.1 today, with 1.0 announced as coming soon and no date. Gemini - the highest-profile host - renders 0.9.1, and Gemini Enterprise's 1.0 upgrade is in progress, undated. An agent built on 1.0-only features, like the bidirectional function calls, does not yet render everywhere the marketing implies. Design for the 0.9.1 floor if reach matters, or accept a fragmented rollout.

The default look is no look. Version 1.0 deleted the theme property on purpose: styling belongs to the host. The corollary nobody puts in the announcement is that the basic catalog with default styling looks like an unstyled form from 2009 - my test card did. The real work of an A2UI adoption is not the protocol, it is implementing the catalog against your design system, component by component. Budget for that, or your agent's screens will look like a wireframe escaped into production.

The vocabulary is small, deliberately. Eighteen components, and in 1.0 the humble Text has exactly two variants: body and caption. There is no heading style, no table, no chart in the basic catalog. Real products will define custom catalogs - Alation's charts and ByteDance's Lynx component set are exactly that - but every custom component is one the agent must be taught and the renderer must implement, per platform. The catalog is your design system's API surface, and it will grow at the speed of your slowest platform team.

Generation reliability is a cost center, not a detail. LLMs writing raw protocol JSON are slow and occasionally wrong, which is why the ecosystem already routes around it: a compact generation format (A2UI Express), server-side macros in Python that expand components programmatically, and decision models that pick components instead of writing text. Google's own examples lean on all three. If your plan is "the big model writes the JSON and we render it", your plan includes a validation-and-retry loop and the latency that comes with it. The prompt-generate-validate loop is not optional garnish; it is the production architecture.

There are no public numbers. No latency benchmarks, no token-cost comparisons, no production usage statistics from Google or the named adopters as of this writing. Atlassian, Alation, Bloomberg and ByteDance building with it is a real signal about direction. It is not evidence about your workload, and anyone who quotes you figures is making them up.

None of these are reasons to ignore A2UI. All of them are reasons to adopt it with pinned versions, a small first surface, and your eyes open.

Should you adopt it? Run your situation

The verdict section below gives you my answer. This picker gives you yours - the same reasoning, weighted by your answers instead of mine.

My verdict: adopt the pattern now, the protocol where it earns it

Here is my call, with the conditions that would change it.

If your agent's answers are approvals, forms, pickers or comparisons, and those answers live in your own product, adopt A2UI now - narrowly. One surface, the worst text answer you currently ship, rendered with the official renderer and the basic catalog, behind a flag. That pilot costs days, teaches you the integration shape, the generation reliability and the styling bill, and it is reversible at every step. This is the same discipline I argue for in choosing between an agent framework and a harness: buy the smallest piece that answers the expensive question.

If the same agent must appear on web and native mobile, or inside assistants you do not control, A2UI is the only option on the table that was designed for it. Hand-rolled JSON means a second and third implementation of the same screens. MCP Apps means iframes and someone else's design language. The catalog model - describe once, render natively everywhere - is the protocol's real moat, and 1.0 is stable enough to build a catalog against if you pin your renderer versions.

If your agent answers in text and text is working, do nothing. A protocol adoption is a cost you pay to fix a problem. No painful forms, no second platform, no problem - and "an open standard exists" is not a problem. Revisit when one of those changes, or when the Jetpack and Gemini hosts finish their 1.0 upgrades and the reach argument gets stronger.

Whatever you decide about the protocol, steal the pattern today. Agent output as structured data, rendered against a component vocabulary you control, validated before it reaches the screen, with user input returning as structured actions. That architecture is right with or without Google's spec, it is most of what an A2UI migration later would need, and it ends the era of parsing your own agent's paragraphs. The flip conditions on my whole position: if renderer packages stall before a stable 1.x, or if a year from now the named adopters have quietly stopped shipping surfaces, the pattern survives and the protocol was a draft worth learning from. I do not expect that outcome. The problem is real, the split is right, and the team behind it is shipping.

FAQ

What is A2UI?

A2UI (Agent-to-User Interface) is Google's open protocol for generative UI. Instead of replying with text, an agent sends JSON messages describing a screen - components from a catalog your app registered, plus a data model to bind them to. Your app renders that description with its own native components. Version 1.0, released November 11, 2026, is the first stable version.

Is A2UI a competitor to MCP Apps or AG-UI?

Mostly no. AG-UI is a transport and event protocol between agents and frontends; A2UI payloads ride on it. MCP Apps lets a server ship an HTML interface that a host renders in a sandboxed iframe; A2UI describes an interface instead, and A2UI screens can run inside MCP Apps hosts. The real competitor to A2UI is hand-rolled JSON rendering - the agent-UI format you invent yourself.

Which frameworks can render A2UI today?

Google ships open-source renderers for React, Angular and Lit on the web, Flutter, and SwiftUI on iOS. The Jetpack Compose renderer for Android is at protocol 0.9.1 with 1.0 support announced as coming soon. Agent SDKs exist for Python, TypeScript and Dart.

Is it safe to render UI an agent generated?

Safer than rendering agent-generated code, by design. The agent can only place components from the catalog you registered, it never sends executable code or markup, and functions that need a user gesture (like opening a URL) cannot be invoked by the agent at all. What the model does not protect you from is intent: an agent can compose a misleading screen from allowed components, so actions still need server-side authorization like any other API call.

Can I use A2UI with my existing Next.js agent?

Yes. A2UI is transport-agnostic and framework-agnostic on the agent side: your route handler or agent loop produces the JSON messages and streams them over SSE, a WebSocket, AG-UI or A2A. The TypeScript agent SDK helps generate and validate messages, but nothing stops a hand-written harness from emitting the same payloads - the wire format is the contract.

Should I adopt A2UI now or wait?

Adopt it now if your agent's answers are forms, approvals or comparisons, and especially if those answers need to land in more than one app. Wait if text answers are not your bottleneck, or if your team cannot absorb spec churn - the protocol is 1.0 but the renderer packages are still 0.15.x. Either way, steal the pattern: structured JSON against a component vocabulary you control.

Comments

No comments yet. Be the first.

Leave a comment

Comments are reviewed before they appear.