All guides

Guide

Next.js AI App Architecture

How Agentic Academy Labs structures Next.js AI apps in Sikar: App Router, Bun APIs, Postgres, RAG, Flutter clients, and what we build in week 1.

Published 2026-08-08 · Updated 2026-08-14

The AI apps we ship from Agentic Academy Labs share one shape: Next.js App Router for the product UI, a Bun-backed API that never leaks keys to the browser, PostgreSQL for app state and often pgvector for retrieval, and Flutter when there is a mobile surface. Interns learn this split on day one because mixing prompts into React components is how demos rot. The architecture below is what we use for client work, not a textbook diagram.

Layers we actually keep separate

  1. Presentation: Next.js server components for shells and lists; client components only for chat, streaming, and file upload.
  2. API: Route Handlers (or a Bun service) that authenticate, rate-limit, and call orchestration. Flutter hits the same HTTP contract.
  3. Orchestration: retrieve, assemble messages, call tools, generate. One function signature so we can swap OpenAI and Anthropic. See OpenAI vs Anthropic for production in India.
  4. Data: PostgreSQL for users, threads, and audit rows. pgvector or a vector store for chunks, always filtered by tenant.
  5. Providers: model adapters behind an interface. Brand names stay out of UI code.
  6. Observability: structured logs for tokens, latency, retrieved ids, and eval scores.

Reference request flow

  1. User sends a message from the Next.js chat client or the Flutter app.
  2. API validates session and quota. We fail closed if org_id is missing.
  3. Retriever fetches top-k chunks for that tenant only.
  4. Orchestrator builds system prompt plus context plus user input. Context is capped; we do not dump the whole handbook.
  5. Model stream returns tokens. The UI renders as they arrive. The server writes the full turn when the stream ends.
  6. A background job scores a sample of turns against the golden set so quality regressions show up before Slack complaints.

Week 1 on a typical engagement

  • Stand up Next.js + Bun + Postgres locally (we run local Postgres first, then the hosted project). Auth and one protected chat route, nothing else.
  • Put provider keys in server env only. A PR that imports an SDK in a client component is rejected in review.
  • Write 15 eval questions before the first pretty UI. Interns own the spreadsheet; engineers own the logger.
  • Stream a stubbed answer so Flutter and web share the same event shape early.
  • Add tenant_id on every retrieval query, even if there is only one customer this week.

Cost and latency knobs that matter

KnobWhat we doWhat goes wrong if you skip it
Context sizeCap chunks; fix chunking before buying a bigger modelToken bills climb and answers get worse
Model splitSmall model for routing, larger for the final answerYou pay frontier prices for 'is this on-topic?'
CacheCache embeddings and hot retrieval per tenantEvery greeting re-embeds the same PDF
RegionDeploy the app near users; keep Postgres warmIST p95 looks fine in a US region demo and dies at 11am

Security checklist we treat as blocking

  • No provider keys in NEXT_PUBLIC_* or Flutter dart-define for production secrets.
  • Retrieval filters include tenant (and often role) before similarity search.
  • Tool outputs are treated as untrusted text, not HTML.
  • Per-user rate limits exist before the first public link. Internship demos have been scraped.
  • Audit log of prompts and sources for any product that touches policy or money.

Failure modes from our lab and clients

  • Server Actions that call the model with no timeout. One hung provider stalls the whole page.
  • Storing chat history only in React state. Refresh loses the thread; Flutter and web disagree.
  • Embedding on every upload on the request path. Large PDFs time out on Vercel; we moved ingest to a queue.
  • One shared prompt file with no version. You cannot explain why Tuesday's answers got worse.

If you are leaving a PHP or Rails monolith, pair this with migrate a monolith to Next.js and PostgreSQL. If the feature is document Q&A, start from RAG vs fine-tuning. Agentic Academy Labs ships this stack under AI web and mobile development and custom AI development. Schedule a call if you want the same skeleton we use in Sikar.

Frequently asked questions

Where should API keys live in a Next.js AI app?
On the server only: Route Handlers, a Bun service, or server actions. Never in the browser or a Flutter client for production provider keys.
Do you stream responses?
Yes. Streaming is the default UX. The server still logs the full turn, tokens, sources, and latency when the stream completes.
Why PostgreSQL instead of a dedicated vector database on day one?
Postgres already holds users and threads. pgvector is enough for many MVPs. We split the vector store when recall, scale, or ops demand it, not because a blog recommended it.
Can Flutter share this architecture?
Yes. Flutter talks to the same authenticated API. We do not duplicate orchestration in Dart.