It is untrusted until validated.
The validation layer is where the application turns probabilistic model output into something deterministic enough to render. Whether a team uses JSON Schema, Zod, Valibot, or another validation library, the application should receive the model response as unknown data and validate it before anything reaches the screen. That validation step should reject unknown component types, malformed props, unsupported actions, and any structure the application does not explicitly understand. Only after the response passes that boundary should it be rendered through the component registry.
With a schema library, the validation boundary might look like this:
const CostSummarySchema = z.object({
 type: z.literal('cost-summary'),
 props: z.object({
  period: z.enum(['current-week', 'current-month']),
  comparisonPeriod: z.enum(['previous-week', 'previous-month'])
 })
});
const AnomalyListSchema = z.object({
 type: z.literal('anomaly-list'),
 props: z.object({
  severity: z.enum(['medium', 'high'])
 })
});
const UIBlockSchema = z.discriminatedUnion('type', [
 CostSummarySchema,
 AnomalyListSchema
]);
function parseUIResponse(response: unknown): UIBlock[] {
 const result = z.array(UIBlockSchema).safeParse(response);
  if (!result.success) {
  return [];
 }
  return result.data;
}
In a real application, the schema would likely cover layout rules, component limits, allowed nesting, action references, and versioning. The point is not the specific library. The point is the boundary.
The model does not get to decide whether its output is safe. The application does.
A fallback path is also essential. If validation fails, the application should not attempt to improvise. It should show a safe fallback, ask the user to rephrase, or return a conventional text response. AI-driven interfaces need graceful failure. A malformed UI description should never become a broken or unsafe screen.
Separate rendering from actions
The most important boundary in generative UI is not rendering. It is execution.
A dynamic interface may include buttons, forms, confirmations, or workflow steps. Those controls may request real operations: shut down an instance, resize a database, open a support ticket, approve a deployment, update a policy, or change account settings.
The model should not execute those actions. It should not decide that an operation is allowed simply because the user asked for it. Instead, action execution should flow through an application-owned action registry.
For example, a model may request a confirmation component:
{
 "type": "confirmation",
 "props": {
  "message": "Do you want to open a remediation task for the unused compute instances?",
  "actionId": "create-remediation-task"
 }
}
But the action itself should be defined and executed by the application:
type UIAction =
 | {
   type: 'create-remediation-task';
   resourceIds: string[];
  }
 | {
   type: 'open-support-ticket';
   category: 'billing' | 'performance' | 'security';
  };
const actionRegistry = {
 'create-remediation-task': createRemediationTask,
 'open-support-ticket': openSupportTicket
};
async function executeAction(action: UIAction, user: CurrentUser) {
 if (!isActionAllowed(action, user)) {
  throw new Error('Action not allowed');
 }
 return actionRegistry[action.type](action);
}
Before an operation runs, the application has to make deterministic decisions that the model should not control. The action must exist in the application’s registry, the current user must be authorized to perform it, the target resources must belong to a context the user can access, and the operation must still be valid in the current state. Some actions may require confirmation, auditing, approval routing, or a final server-side permission check before anything changes.
These questions cannot be delegated to the model. They belong to the application and, ultimately, to the back-end systems that enforce the business rules.
The model can help generate the path. It cannot become the authority.
State still belongs to the application
Generative UI also creates a subtle state-management problem.
In a traditional application, the front end knows where state lives. Billing data, user permissions, resource metadata, anomaly status, remediation tasks, and workflow progress are loaded, cached, invalidated, and updated through known application paths.
An AI-driven interface can blur that boundary. The model may summarize state, infer state, remember conversation context, or describe a screen based on previous messages. If teams are not careful, the generated interface becomes a second hidden state system.
That is dangerous.
The UI may say a compute instance is unused even though its status has changed. It may show a remediation option based on stale billing data. It may produce a confirmation message that no longer matches the current workflow. It may remember something from the conversation that the application itself has not verified.
The application must always remain the authority on state.Â
The model can help decide which components to display, but those components should read real state from the application and its APIs. A CostSummary component should fetch or receive billing data through the same trusted path as any other part of the product. A remediation action should update state through the normal application flow. A confirmation component should not become the source of truth for whether an operation is possible.
Generative UI should be a projection of application state, not the owner of it.
This distinction becomes even more important in agentic applications, where interfaces may change over several turns of conversation. A user may ask a question, inspect a result, request an action, change their mind, and return later. The application needs a reliable model for what happened, what is pending, what failed, and what still requires human approval.
That cannot live only in the model’s context window.
Design for controlled composition
The future of generative UI is not arbitrary run-time code generation. It is controlled composition.
The model should be able to assemble experiences from trusted capabilities: components, layouts, actions, validation rules, and state transitions that the application exposes intentionally.
That gives developers the best of both worlds.
The interface can adapt to the user’s goal, but the system remains testable. The model can choose the right UI blocks, but the design system stays intact. The user can move through dynamic workflows, but permissions and business rules remain deterministic. The application can feel intelligent without becoming unpredictable.
This is also a better mental model for front-end teams. Generative UI is not a replacement for front-end architecture. It increases the need for front-end architecture.
Teams still need component systems. They still need run-time validation. They still need state ownership. They still need accessibility standards. They still need action boundaries. They still need server-side authorization. AI does not remove these concerns. It makes weak boundaries easier to expose.
In this model, the user expresses intent and the model responds with structured UI intent. The application validates that response, renders it through a component registry, and routes any requested behavior through an action registry. Application state remains the source of truth, while the server remains responsible for final authorization.
That is the boundary production systems need.
AI can help developers generate complete features during development. That code can and should go through review, testing, and normal delivery. But when AI participates in a running application, the run-time contract needs to be much narrower. The live model should describe what the user interface should express, not generate unchecked code that the product executes.
The better approach is to give AI a component system.
Let the model compose. Let the application control. Let the user experience become more dynamic without sacrificing the architecture that makes software reliable.

