How Agent-Native Handles Dynamic Content: SSR, Route Discovery, and Runtime Loading

Agent-Native handles dynamic content through a three-layer architecture that uses lazy imports for server-side rendering, pattern-based route discovery for API endpoints, and client-side recovery scripts to manage failed dynamic imports.

BuilderIO/agent-native treats dynamic content as any resource resolved at runtime rather than baked into the build. The framework isolates this behavior across server-side rendering, API route discovery, and client-side error recovery. This approach ensures that React Router pages, dynamic API segments, and optional peer dependencies load only when requested.

Server-Side Rendering with Lazy Virtual Imports

The SSR layer defers loading the React Router server build until the first request hits the catch-all route. Instead of bundling the server build statically, the handler in packages/core/src/server/ssr-handler.ts uses a dynamic import() to load virtual:react-router/server-build.

The Virtual Module Pattern

The virtual module lives inside the project template rather than node_modules, allowing Vite to apply its dev-plugin transformations. This avoids 302 fallback errors that would occur if the import resolved from external dependencies.

// packages/core/src/server/ssr-handler.ts
export default createH3SSRHandler(
  () => import('virtual:react-router/server-build')
);

The dynamic import wrapper caches the promise after the first load, ensuring subsequent requests reuse the compiled server build without re-executing the import.

Dynamic Route Discovery for Deployment

Agent-Native parses Nitro-style file trees to identify API routes containing dynamic segments like [id] or [...catchall]. The parseRouteFile function in packages/core/src/deploy/route-discovery.ts converts bracket notation into colon-prefixed parameters and flags routes as dynamic.

Pattern-Based Route Parsing

When processing files such as api/users/[id].get.ts, the utility transforms [param] into :param notation. This ensures the deployment configuration recognizes these paths as dynamic functions rather than static assets.

// packages/core/src/deploy/route-discovery.ts
import { parseRouteFile } from '@agent-native/core/deploy/route-discovery';
const info = parseRouteFile('api/users/[id].get.ts');
// → { method: 'get', route: '/api/users/:id', dynamic: true }

The generated Cloudflare or Netlify function config routes requests to server functions instead of cached HTML pages when dynamic segments are detected.

Runtime Lazy Loading for Edge Compatibility

To maintain compatibility with edge runtimes where require() would crash, Agent-Native implements lazy loading for optional dependencies and heavy server plugins. The getFs() helper in packages/core/src/deploy/route-discovery.ts demonstrates this pattern.

The Lazy FS Loader Pattern

The helper caches the fs module promise after the first dynamic import, keeping the core bundle small and allowing execution in environments without native filesystem access.

// packages/core/src/deploy/route-discovery.ts
let _fs: typeof import('fs') | undefined;

async function getFs() {
  if (!_fs) _fs = await import('node:fs');
  return _fs;
}

This approach applies to optional peer dependencies like the ACP SDK and scheduling UI, which load only when explicitly requested.

Client-Side Error Recovery for Stale Chunks

Dynamic imports can fail when CDN chunks become stale after a deployment. Agent-Native includes a recovery script in packages/core/src/client/vite-dev-recovery-script.ts that detects failed dynamic module fetches and reloads the page.

Failed Import Detection

The script listens for unhandled rejections containing "Failed to fetch dynamically imported module". When detected, it either reloads the page or navigates to a fresh target, preventing frozen UI states.

// packages/core/src/client/vite-dev-recovery-script.ts
if (err.message.includes('Failed to fetch dynamically imported module')) {
  location.reload();
}

This mechanism runs in both Vite dev server and production bundles, ensuring users always receive the latest chunks.

Migration Guards for Headless Content

The migration tooling in packages/migrate/src/adapters/nextjs.ts enforces that pages fetched from headless CMS sources remain dynamic rather than being stored in Builder's content blobs. It scans for route patterns containing colons or wildcards.

Dynamic Page Detection

The adapter checks path values for dynamic indicators like :param or *, ensuring these routes are served by approved headless sources rather than static generation.

// packages/migrate/src/adapters/nextjs.ts
const isDynamic = pathValue.includes(":") || pathValue.includes("*");

This gate prevents accidental staticification of content that must resolve at runtime.

Summary

  • Lazy SSR imports: The ssr-handler.ts loads React Router server builds dynamically via virtual:react-router/server-build to avoid 302 fallbacks.
  • Pattern-based discovery: route-discovery.ts converts [param] to :param and marks routes as dynamic for edge function deployment.
  • Edge-compatible loading: The getFs() helper uses cached dynamic imports to load Node.js modules only when needed.
  • Client recovery: The vite-dev-recovery-script.ts reloads pages when stale chunks cause dynamic import failures.
  • Migration enforcement: The Next.js adapter ensures headless CMS pages stay dynamic by detecting colon and wildcard patterns.

Frequently Asked Questions

How does Agent-Native load React Router for SSR?

Agent-Native uses a dynamic import() to load virtual:react-router/server-build inside the createH3SSRHandler function in packages/core/src/server/ssr-handler.ts. This loads the compiled server bundle only when the first request hits the catch-all route, caching the result for subsequent requests.

What pattern does Agent-Native use to identify dynamic API routes?

The framework parses Nitro-style file trees in packages/core/src/deploy/route-discovery.ts, converting bracket notation like [id] into colon-prefixed parameters like :id. Routes containing these patterns are flagged as dynamic, ensuring deployment targets route them to server functions rather than static assets.

How does Agent-Native recover from failed dynamic imports on the client?

The vite-dev-recovery-script.ts monitors for unhandled rejections containing "Failed to fetch dynamically imported module". When detected, it triggers a page reload to fetch fresh chunks from the CDN, preventing UI freezes caused by stale JavaScript bundles.

Why does Agent-Native use dynamic imports instead of require()?

Dynamic imports enable lazy loading of optional peer dependencies and Node.js built-ins like fs while maintaining compatibility with edge runtimes where require() would crash. This pattern keeps the core bundle small and allows the same code to execute in both Node.js and edge environments.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →