React gets all the press, but for multi-tenant enterprise apps with complex permissions and real-time requirements, our stack is hard to beat. Here's why.
If you ask most developers what stack to build a SaaS in, you'll hear some variation of the same answer: React frontend, Node.js or Python API, PostgreSQL. It's the default. It works. There's nothing wrong with it.
But defaults aren't always right for every context. When the context is enterprise SaaS — multi-tenant, complex role-based permissions, real-time communications, a mobile app that needs to work offline, and a small engineering team that needs to move fast — I consistently reach for a different stack. Blazor WebAssembly, ASP.NET Core, and .NET MAUI.
This isn't contrarianism. It's the result of building OpsFlow — 131 Blazor pages, 50+ API controllers, iOS and Android apps, real-time SignalR, Stripe billing, MFA, and Azure cloud — and seeing what the stack actually looks like under production load.
What Enterprise Apps Actually Need
Consumer apps and enterprise apps have fundamentally different requirements. A consumer app needs to be fast to iterate on, easy to demo, and simple enough that a user figures it out in 30 seconds. An enterprise app needs to be reliable, secure, auditable, and capable of expressing complex business logic without becoming a maintenance nightmare.
- Role-based access control with dozens or hundreds of permission policies
- Multi-tenancy: strict data isolation between organizations, shared infrastructure
- Real-time updates: technicians in the field need to see changes instantly
- Offline capability: mobile workers in facilities with no connectivity
- Auditability: who did what, when, and why — for compliance and accountability
- Billing integration: subscriptions, seat licensing, usage tracking
OpsFlow has 249 permission policies. That's not unusual for enterprise software. Managing that complexity in a JavaScript frontend across a JavaScript API is possible — but the type safety story is painful. You're constantly bridging the gap between what the server knows and what the client knows.
Blazor WASM: What It Is and What It Is Not
Blazor WebAssembly runs C# in the browser via WebAssembly. You write your UI components in C# and Razor syntax, and the .NET runtime executes in the browser. For developers who know .NET, the productivity gain is significant — you're writing in one language, with full IntelliSense, across the entire stack.
It's not the right choice for every app. Initial load times are higher than a React app because the .NET runtime has to be downloaded. For a consumer app where first impressions are everything, that matters. For an enterprise app where users authenticate and stay logged in for hours at a time, it's a one-time cost that becomes irrelevant.
The payoff: sharing models, enums, and validation logic between the API and the frontend without any code duplication. No more keeping TypeScript interfaces in sync with your API contracts. One source of truth.
The Full Stack Advantage
When your API is ASP.NET Core and your frontend is Blazor, you get something that no cross-language stack can replicate: true end-to-end type safety without code generation. Your domain model is defined once. Your validation attributes propagate from the server. Your permission policies are enforced at the API layer and reflected in the UI layer — from the same C# attributes.
For OpsFlow, this meant defining a WorkOrder entity, its business rules, its permission requirements, and its validation constraints in one place — and having all of that enforced consistently everywhere the entity is touched.
One language, one type system, one team. When you're building complex business logic, that's not a small advantage.
.NET MAUI for Mobile: One Codebase, iOS and Android
.NET MAUI (Multi-platform App UI) lets us write the mobile app in C# and ship it to both iOS and Android from a single codebase. For the OpsFlow mobile app, this meant our field technicians could use the same application — with offline-first sync, QR code scanning for asset tracking, and push notifications — on whatever device they had.
The alternative — writing a React Native app — would have introduced a third language and runtime into the stack, with a separate team context and a different set of debugging tools. For a small studio building a production enterprise app, that cognitive overhead compounds quickly.
When React IS the Right Choice
To be clear: we build in React too. For consumer-facing products, marketing sites with complex interactivity, and projects where the frontend team is JavaScript-native, React is excellent. Next.js (like this site) is our default for public-facing web.
The choice isn't about which stack is better in the abstract. It's about which stack is right for the specific engineering problem you're solving. For multi-tenant enterprise SaaS with a mobile component and a small team, the .NET stack has consistently proven faster to build in, easier to maintain, and more reliable at scale.
OpsFlow running in four school districts is the proof. Not a benchmark — a production system.

Paul Evans
Founder & Engineer, Phaseable
I've been building software for 20+ years. I founded Phaseable to build industry-defining vertical SaaS products and help founders with niche problems turn them into real businesses.
Keep Reading
How OpsFlow Went From a Conversation to a Live SaaS in 4 School Districts
It started with a relationship, a real pain point, and a problem no existing software solved well. Here's the full origin story.
Read MoreVertical SaaSHow to Find a Vertical SaaS Opportunity Worth Building
The best vertical SaaS products come from insiders who've lived the problem. Here's a framework for identifying the gaps worth solving.
Read More