Building Scalable Web Apps: A Deep Dive into Modern Architecture and Tech Stacks
When building a modern, data-intensive web application, establishing a scalable, maintainable, and highly performant foundation is critical. In this post, we'll dive deep into an optimized project folder architecture, explore the cutting-edge packages we rely on, and explain the core philosophy behind our Feature-Driven Development (FDD) approach.
The Tech Stack: Packages Powering Modern Apps
Our architecture relies on a modern, type-safe stack designed for both an exceptional developer experience and blazing-fast end-user performance. Here is a breakdown of the key technologies we use:
Frontend & Full-Stack Capabilities
- TanStack Start: We choose TanStack Start for full-stack SSR and hydration capabilities. It leverages Vite and provides fully type-safe, code-based routing, ensuring that broken links and missing parameters are caught at compile time.
- React 19 & Vite: We leverage the latest features of React 19 alongside Vite for rapid local development and optimized production builds. The React Compiler (
babel-plugin-react-compiler) automatically memoizes components, drastically reducing boilerplate and manual performance tuning. - Tailwind CSS v4: For highly customizable, utility-first styling with the latest engine performance improvements.
- Component Libraries: A robust combination of
@base-ui/react, Radix UI primitives, andlucide-reactfor building accessible, premium interfaces without sacrificing customizability.
State Management & APIs
- TanStack Query: Handling robust async state management, caching, and optimistic UI updates for a seamless, zero-latency feel.
- ORPC: Using
@orpc/server,@orpc/client, and@orpc/tanstack-queryfor fully type-safe RPC API communication between our client and server. This eliminates the need for manual API typing and keeps the backend and frontend in perfect sync.
Backend & Database Layer
- Prisma ORM: Powering our data layer with strongly typed database access (
@prisma/clientand@prisma/adapter-pg), making complex relational queries safe and intuitive. - Better Auth: Providing a secure, comprehensive authentication system right out of the box.
- Zod: Heavily used for schema validation on both the client and server, guaranteeing data integrity at the boundaries.
High-Level Project Architecture
A well-structured repository promotes separation of concerns while keeping related code close together, minimizing context switching. Here is a look at the core src/ directory:
src/
├── components/ # Global shared UI components (e.g., buttons, layouts)
├── config/ # Application configuration files
├── features/ # Feature-based modules (The core of our FDD architecture)
├── hooks/ # Global custom React hooks
├── integrations/ # Third-party integrations (e.g., payment gateways, AWS S3)
├── lib/ # Utility functions and shared libraries
├── routes/ # TanStack Start file-based route definitions
├── server/ # Global server setups and middleware
├── styles.css # Global CSS (Tailwind entry point)
└── types/ # Global TypeScript type definitions
The beating heart of this architecture is the src/features/ directory. Let's explore how we structure it to maximize team velocity.
Feature-Driven Development (FDD): Vertical Slices
To ensure our codebase scales gracefully as the application grows, we use a strict Vertical Slices Architectural pattern. Instead of organizing files strictly by technical role (e.g., grouping all controllers in one folder and all models in another), we group code by Feature (e.g., users, billing, dashboard).
This approach drastically reduces cognitive load because all the context needed to understand or modify a feature is located in one place. Inside each feature directory, we split the code into two distinct layers: domain and ui.
1. The Domain Layer (Server & Business Logic)
The domain/ directory contains server-side logic, database interactions, and API definitions. Crucially, the domain folder must NEVER import from the UI folder. This ensures business logic remains independent of presentation.
[feature].schema.ts: The single source of truth for all Zod schemas and TypeScript types. We avoid separatetype.tsfiles to keep definitions consolidated.[feature].repo.ts: The Repository layer for Prisma database access. By abstracting DB calls here, we can easily manage complex transactions without cluttering business logic.[feature].service.ts: The Business Logic layer that orchestrates data and enforces domain rules.[feature].contract.ts: ORPC contract definitions mapping API input/output signatures.[feature].router.ts: API endpoint implementations. By tying this to specific features, we can securely scope our procedures via auth middleware by default.
2. The UI Layer (Client & Presentation)
The ui/ directory houses React components and client-side logic specific to the feature.
components/: Feature-specific UI components (e.g.,ProfileForm,BillingTable). We favor small, composed components over massive monoliths.hooks/: Custom hooks wrapping ORPC mutations and queries. This is where we implement Optimistic UI updates, caching strategies, and data transformations.view/: Page-level container components assembling smaller components into full views, which are then cleanly imported bysrc/routes/.
The True Benefits of Vertical Slices
- Unmatched Predictability: Developers know exactly where to find the database query, the API route, and the React component for any given feature—they are all in the same folder. This eliminates hunting through deeply nested directories.
- React Compiler Optimization: Keeping stable constants outside components allows the React 19 Compiler to perfectly optimize our UI without manual hooks.
- Robust Security: By mandating authentication middleware at the feature router level, endpoints are secure by default, and access control logic lives next to the data it protects.
- Scalable Team Workflows: Multiple developers can work on separate features simultaneously with near-zero merge conflicts, as their changes are isolated to different vertical slices.
This architecture allows engineering teams to remain agile and robust, providing a premium experience for end-users while keeping the codebase a joy to work in.