A Startup Web Stack for the AI-Agent Era: Next.js, MUI and Firebase
A startup web stack for the coding-agent era: Next.js, MUI, Firebase, Vercel and PostHog, with a minimal agent setup and the reasoning behind each choice.
This article is published in English.
Sources: The Teach Stack for Building Full-Stack Apps in the AI-Agentic Era (2026 Edition)
Picking a stack when the code is half machine-written
Coding agents such as Claude Code and Codex have changed how software gets built. Iteration is much faster, which only helps if the code stays maintainable and scalable enough for the project to keep evolving.
Early-stage startups live on iteration speed. Requirements shift fast, features land daily and code is rewritten constantly. In that setting, the technologies chosen need to support quick change without making the user experience worse.
The stack below comes from roughly four years of experimenting with modern tools on a real learning platform. It covers authentication, UI, backend, hosting, testing and more, and the goal throughout is fast building on top of a codebase that humans can still maintain, with infrastructure that scales.
Keeping agents and code simple
Agents make rapid improvement easy: bug fixes, new features and performance work all arrive quickly. They also make over-engineering easy, since adding thousands of lines is trivial. The discipline is to resist solving problems that don't exist yet and to keep code, infrastructure and user experience simple.
A small, plain setup helps even in this era of agentic development. Agents coordinate better, features ship sooner, bugs are easier to fix, and people can still maintain what's there.
The approach to agents on production code is balanced and the setup is modest:
- Keep
AGENTS.mdorCLAUDE.mdas short as possible. Put in it only what gets repeated in every conversation, along with project-specific details agents keep getting wrong. - Oversized instruction files can hurt a model's performance and make it less useful.
- Install only the skills a conversation needs, and remove them when it ends.
- Fewer skills and a smaller instruction file tend to work better than more.
- Some skills are worth having on hand but not permanently, because leaving them installed pollutes the context window. Useful areas are UI/UX design, React and Next.js, Firebase, and PostHog.
On MCP servers, PostHog's provides easy access to error traces and logs, which speeds up debugging. Context7 serves up-to-date library documentation to the model so agents can consult the latest docs for libraries and frameworks. Most of the time agents work things out without help from an MCP server, so enabling them is rarely necessary.
The rule of thumb is that every extra tool, skill or server competes for the model's attention. Anything that doesn't earn its place in the current task is better left out, and the setup can be revisited whenever a recurring mistake shows up that a one-line instruction would fix.
Frontend: React and Next.js
React is the top pick for the core of many full-stack projects. Vue and Svelte are options, but React's large library ecosystem makes adding features and changing direction easier, and that's why developers favor it.
The weak spot is search engines. Google and Bing use bots that read a page's HTML, and a React page usually starts with an empty body from the server. For a site to appear in search results, the first response from the server has to contain HTML filled with the right page information.
Next.js handles this. It's a React framework offering server-side rendering and static generation, so pages render on the server first and the HTML is then sent to the browser, which means the initial content carries what bots need. Afterwards only the necessary JavaScript goes to the client, keeping the bundle small. Both user experience and crawler understanding improve.
The current standard in Next.js projects is the app router, which makes features like incremental static regeneration and partial pre-rendering easy to use, and they make an app feel faster. New projects should start with it.
React is moving toward the server side, getting somewhat closer to PHP in spirit, and the app router offers a good developer experience for server-first components. Caching, Turbopack and an agent-friendly setup make building and iterating quick.
UI: a component library over custom design
Traditional web development moves through planning, UI/UX design, implementation and many rounds of back and forth between designers and developers. Startups can't afford a long cycle.
The most efficient approach has been to choose a solid UI framework, MUI in this case, and follow a design template. The alternative is having a designer draw everything in Figma and then having developers rebuild it in React. Keeping a single source of truth in the codebase saved months.
MUI offers a rich set of customizable components covering common needs. Everything can be changed, but the defaults are good enough that most components end up used with their stock behavior and look. It also ships a large collection of icons usable as React components, so including them is trivial.
There are alternatives:
- shadcn/ui is modern and popular, though copying library code into your own codebase through a CLI is a questionable practice to some.
- Ant Design is a strong option.
- Chakra UI works as a UI framework too.
- HeroUI, formerly NextUI, is also good.
Some people prefer styled-components or Tailwind CSS. With either, a lot of CSS still gets written, which compares poorly with a UI framework for developer experience, particularly when the aim is to avoid designing every page from scratch.
For inspiration, template stores help. MUI's own store has many attractive UI templates, and Dribbble carries React templates too. Another route is asking an agent to produce several prototypes and picking the best, and adding a UI/UX skill improves what it generates.
Forms
Forms make up a big share of full-stack work. Zod and React Hook Form pair well and cover nearly everything. Zod handles schema validation, including types, bounds, lengths and enums, and React Hook Form provides a flexible API for interacting with the form. Together they allow nested components that share one form, complex validations and live updates of data. Forms start to feel almost too easy.
Because the validation schema is a plain TypeScript-friendly object, the same rules can describe what a form accepts and what a backend function expects. That removes a whole class of mismatches between what the UI allows and what the server rejects, and agents read a schema far more reliably than they read validation logic scattered through handlers.
Backend, authentication and database
Firebase and Supabase offer backend as a service, scaling to millions of users with no infrastructure of your own to maintain. The stack here uses Firebase for authentication, storage, the Firestore database and serverless functions that hold custom backend logic.
Authentication
Clerk is a strong product for authentication, but Firebase's default system works well enough here. Firebase also ships a package called firebaseui-web that sets up authentication without writing any UI code. For it to work smoothly, the Next.js app is also deployed on a dedicated auth subdomain so that Firebase can handle sign-in without problems.
Database
In a traditional build, with a separate frontend and a backend over a database, the frontend triggers many API calls that change database entries. In many projects about 80% of those calls are plain CRUD operations, and the other 20% are more complex, such as updating several entries or aggregating data from several sources. Firebase optimizes for the 80%, making it easy to manipulate data from the frontend without redundant endpoints.
Two components make that work.
- Firestore Rules. Access control and permissions live in one file,
firestore.rules. API endpoints don't have to check permissions in every function, since Firebase verifies automatically whether a user may read a piece of data or create, update or delete it. This separation removes a lot of boilerplate. - Firestore client SDK. Creating, reading, updating and deleting go through the Firebase SDK, which also supports real-time listeners, counter increments and batched updates, all checked against
firestore.rulesautomatically.
There's one caveat, the mental model for storing data. Firestore is optimized for reads, which usually dominate, so it encourages denormalized data. That can feel unnatural for people from an SQL background, and a good conference talk on Firestore data modeling is worth watching.
Overall, Firestore delivers a strong user experience, especially through real-time change listeners, along with a good developer experience, letting the application adapt quickly to changing needs.
New projects are best started on Firestore's Enterprise edition in Native mode. It supports features missing from the older standard tier, such as pipeline queries and built-in full-text search, giving the flexibility of a MongoDB-like database along with Firestore's ease of use.
Serverless functions
The client code stays deliberately simple, with the involved parts isolated in backend code inside serverless functions. Keeping the frontend dumb and the backend smart has worked well. Firebase Functions can hold any backend code, and they can be triggered by a plain HTTP request, by a Firestore entry being created or updated, or on a schedule as a cron job through Pub/Sub. All the server-side functionality can then live in separate, self-contained functions.
BaaS tools like Firebase save a lot of time and mostly just work. Debugging issues from database irregularities or failed migrations is a rare event.
AI features
AI is a major part of modern web apps, and many products embed chatbots and agents. Vercel's AI SDK handles integration with different model providers and the creation of custom agents here. Its strength is how easy it is to plug in different models and switch between them, with a cleaner developer experience than any model-specific SDK.
Tests
Testing is probably the most controversial topic, particularly for startups with constantly changing requirements. In the early days there were no tests. As the product grew, changing existing code with confidence that production would keep working became nearly impossible, so tests were introduced for the backend, specifically the service layer of the Firebase Functions. The frontend is untested because it's kept dumb, while the smart backend is tested against edge cases.
Backend tests use Jest, with faker.js to generate fake data inside tests. They run against a separate Firebase project so production stays untouched, which also allows quick iteration with no worry about affecting users. Once the tests pass, the new Functions version goes to production.
The reasoning behind testing only the backend is cost. A frontend that merely displays data and calls functions has little logic worth asserting, and UI tests tend to break whenever the design changes, which in a young product is constantly. Backend logic is where a quiet regression can corrupt data or charge a user wrongly, so that's where the effort goes.
Refactoring
As a project grows, features change, requirements shift and things age, so refactoring becomes unavoidable. Two things contribute most to modifying code with confidence: TypeScript and solid integration tests. TypeScript keeps types safe after changes, and the integration tests confirm the logic still works.
Refactoring comes up more often than expected. There hasn't been a six-month stretch without some major refactor, because the platform keeps changing and adopting some technologies means large code changes. The two biggest milestones were moving from plain React to Next.js and then from the Next.js pages router to the app router.
Hosting
With the backend entirely on Firebase (Google Cloud), the frontend is deployed to Vercel, which offers the most convenient infrastructure for shipping Next.js. Its GitHub integration works well with branches and needs no manual setup:
- A push to
mainis deployed to production automatically. - A push to any other branch triggers a Preview deployment with its own link, so each branch can be viewed live, which makes iterating fast and convenient.
Reviewing a change then means opening a link and not pulling a branch and running it locally, which suits a small team where designers, product people and engineers all want to see work in progress without any setup on their own machines.
Analytics and monitoring
Knowing who the users are and how they use the product is valuable. It can save weeks or months of development by showing what to prioritize, and good monitoring improves the experience by surfacing common bugs.
PostHog covers general analytics and product monitoring here, including session replay, exception capture, logs and production sourcemaps. Google Analytics for Firebase is a free alternative that takes more setup, and Sentry is a somewhat pricier one. All of them help with knowing users, but nothing replaces talking to them directly.
Email remains one of the most dependable ways to stay in touch with users, send updates and keep them engaged. The stack recently moved from Sendgrid to react-email together with Resend.
react-email makes highly customizable emails by turning each one into a React component. Resend integrates well with it and has good pricing. Since emails are React components, they're committed to version control with the rest of the code, so every change is tracked in one place.
Previewing and testing templates is just as easy, since the same component renders in a browser during development and produces the HTML that goes out to inboxes.