DEV Community

Cover image for I Built a Production-Ready AI Agent with NestJS and React (and You Can Steal It)
Royshell
Royshell

Posted on

I Built a Production-Ready AI Agent with NestJS and React (and You Can Steal It)

TL;DR

Building an AI agent in 2026 is way less scary than it sounds.

Most of the time, it’s just clean backend architecture + smart API calls to LLMs.

I built a production-ready boilerplate using NestJS + React that gives you a working AI agent (with streaming chat UI) in under a minute.

👉 Steal the code here:

https://github.com/Royshell/ai-agent-nest-react-boilerplate

Fork it. Copy it. Rip it apart. That’s what it’s for.


“AI Agents” Sound Big. The Reality Is Smaller (and Better)

If you hang around developer Twitter or LinkedIn long enough, “AI agents” start to feel like this massive, abstract thing:

  • autonomous reasoning
  • tool orchestration
  • memory systems
  • workflows and planners

And sure — those things exist.

But here’s the reality for most real-world AI apps:

An AI agent is just an application that calls an LLM API in a structured way.

You don’t need to understand transformers.

You don’t need to train models.

You don’t need a PhD.

You need:

  • an API key
  • a backend endpoint
  • a clean way to stream responses
  • a UI to display them

That’s it.


The Basic AI Agent Flow (No Magic)

Almost every modern AI app follows the same steps:

  1. Sign up to an LLM provider (Gemini, OpenAI, Claude, etc.)
  2. Generate an API key
  3. Store it in your backend .env
  4. Create an endpoint that sends prompts to the LLM
  5. Stream tokens back to the client
  6. Render them in the UI

Different providers, same idea.

HTTP + JSON + streaming.

This boilerplate focuses on getting that flow right, cleanly and predictably.


Why NestJS for the Backend?

I wanted a backend that feels:

  • production-ready
  • readable
  • easy to extend later

NestJS gives you:

  • clear module boundaries
  • dependency injection
  • controllers vs services separation
  • structure without over-engineering

In this project, the backend is built in a module-driven design.

There’s a dedicated module responsible for AI / LLM interaction — not scattered logic inside random controllers.


Example: Chat Endpoint (Complete & Simplified)

Below is a fully copyable, simplified version of the chat endpoint.

import { Body, Controller, Post, Res } from '@nestjs/common';
import { Response } from 'express';
import { AgentService } from './agent.service';
import { ChatDto } from './dto/chat.dto';

@Controller('chat')
export class ChatController {
  constructor(private readonly agentService: AgentService) {}

  @Post()
  async chat(@Body() dto: ChatDto, @Res() res: Response) {
    // The controller stays thin and boring on purpose
    return this.agentService.streamChat(dto, res);
  }
}
Enter fullscreen mode Exit fullscreen mode

The controller does almost nothing — by design.

All the interesting logic lives inside the agent service, which:

  • talks to the LLM provider
  • handles streaming
  • stays isolated from HTTP concerns

That separation is intentional and makes the system easy to extend later.


“But This Is Just a Chatbot…”

Yes.

And that’s the point.

A chatbot is the simplest possible AI agent:

input → reasoning → output
Enter fullscreen mode Exit fullscreen mode

Once you have that working:

  • the controller can accept any input (not just chat messages)
  • the agent can call tools
  • the agent can fetch data
  • the agent can write to databases

The UI might stay a chat, but the backend can evolve into:

  • internal assistants
  • workflow agents
  • data-aware tools
  • system controllers

The chat is just the interface, not the limitation.


LLM Providers Are Swappable by Design

The main branch uses Google Gemini because:

  • the free tier is usable
  • the API is simple
  • no credit card required to start

But the architecture doesn’t care.

Each provider lives in its own branch:

  • openai
  • anthropic
  • ollama (local models)

Same agent interface.

Different implementations.

No vendor lock-in.


MCP, Tools, and Databases (What’s Next)

Once you have:

  • a clean agent layer
  • a predictable API boundary

You can start connecting real capabilities.

The next step in this project is adding MCP (Model Context Protocol) placeholders.

That opens the door to:

  • external tools
  • databases
  • internal APIs
  • contextual data sources

Think:

  • querying a database
  • calling internal services
  • reading documents
  • executing structured actions

The current version doesn’t implement MCP yet — but the architecture is ready for it.


The Frontend: Simple, Modern, and Boring (In a Good Way)

The frontend is built with React + Vite, following modern best practices:

  • small, focused components
  • custom hooks for logic
  • streaming message rendering
  • clean separation between UI and data fetching

There’s:

  • a chat component
  • hooks that manage streaming state
  • minimal styling (on purpose)

It’s not a design system.

It’s a starting point.

Replace it. Restyle it. Or keep it.


This Is a Boilerplate, Not a Framework

That distinction matters.

You’re encouraged to:

  • copy files
  • delete parts
  • rewrite logic
  • break conventions

This repo is opinionated enough to be useful — but loose enough to disappear once you’ve taken what you need.


Community First

Seriously:

  • steal the code
  • fork it
  • open PRs
  • suggest changes
  • build weird stuff with it

If it saves you a few hours of setup — it did its job.


Final Thoughts

AI agents aren’t magic.

They’re software systems that talk to APIs.

If you can build a backend endpoint and a frontend UI, you can build an AI agent.

Hopefully, this boilerplate helps you skip the boring parts and get straight to building something interesting.

Happy hacking 🚀

And yes — please steal it.

Top comments (0)