Why Tech Stack Decisions Matter More Than You Think

When you are building a SaaS product, your tech stack is not just a list of logos for your landing page. It is the foundation that determines how fast you can ship features, how reliably your system runs under load, how secure your users' data is, and how easy it is to onboard new engineers. Get it wrong, and you spend the next three years fighting your own infrastructure instead of building product.

At TulsiX, we spent serious time evaluating our options before writing the first line of CAPilot code. This article is a transparent walkthrough of what we chose, why we chose it, and how it all fits together. If you are a technical founder, an engineering lead, or just someone curious about how modern SaaS products are built in India, this is for you.

The Frontend: React

For the CAPilot frontend, we chose React. Not because it is the most popular framework — though it is — but because it solves the specific problems we face as a practice management platform.

Component Architecture for Complex UIs

CAPilot is not a simple CRUD application. A single screen might show a client's profile, their compliance status across six different filing types, a task list with assignments, recent invoices, and uploaded documents. React's component model lets us build each of these as an isolated, reusable piece and compose them into complex views without the code becoming unmanageable.

We use a clear component hierarchy: page-level components handle routing and data fetching, section components manage layout, and atomic components (buttons, inputs, status badges, date pickers) ensure consistency across the entire application. This means when we update the design of a status badge, it changes everywhere — the client dashboard, the task list, the compliance calendar — without touching each page individually.

Ecosystem and Hiring

The React ecosystem is mature. Libraries like React Router for navigation, React Query (TanStack Query) for server state management, and Zustand for client-side state give us battle-tested solutions for common problems. We are not reinventing the wheel; we are building product features.

Equally important: React is the most widely known frontend framework among Indian engineers. When we hire, we are not asking candidates to learn a niche technology. They can be productive on day one.

TypeScript Everywhere

We use TypeScript across the entire frontend codebase. This is non-negotiable for us. When your application has hundreds of components passing data between them, type safety catches entire categories of bugs before they ever reach a user. The autocomplete and refactoring support in modern editors (we use VS Code) makes development faster, not slower.

TypeScript is not about writing more code. It is about writing correct code — and catching mistakes at compile time instead of in production at 2 AM.

The Backend: .NET 8

For the API layer and business logic, we chose .NET 8 (C#). This surprises some people who expect an Indian startup to be running Node.js or Python. Here is why .NET was the right call for us.

Performance That Scales

.NET 8 is one of the fastest web frameworks available, consistently ranking near the top of the TechEmpower benchmarks. For a SaaS product that needs to handle hundreds of concurrent users querying client records, generating invoices, and running compliance checks, raw performance matters. We do not want to throw hardware at a slow runtime when a faster one is available at the same cost.

The performance advantage becomes especially important during peak periods — ITR filing season, GST return deadlines — when every CA firm on the platform is active simultaneously. .NET handles these spikes without breaking a sweat.

Type Safety and Enterprise Readiness

C# is a strongly typed language with excellent support for patterns that matter in business software: dependency injection, middleware pipelines, data validation attributes, and structured error handling. When you are building financial software — invoicing, billing, compliance tracking — you need guardrails that prevent subtle bugs from corrupting data.

We use Entity Framework Core as our ORM, which gives us type-safe database queries, automatic migration management, and a clean abstraction over SQL Server. Combined with C#'s nullable reference types, we catch null reference errors at compile time rather than discovering them when a user tries to generate an invoice.

The .NET Ecosystem

The .NET ecosystem provides built-in solutions for authentication (ASP.NET Identity), authorization (policy-based), API documentation (Swagger/OpenAPI), background job processing (hosted services), and email sending. We also use libraries like FluentValidation for request validation, AutoMapper for object mapping, and Serilog for structured logging. These are not experimental libraries — they are mature, well-maintained, and used in production by thousands of companies.

The Cloud: Microsoft Azure

Our entire infrastructure runs on Microsoft Azure. This was a deliberate choice driven by several factors.

PaaS-First Architecture

We are a small team. We do not have — and do not want — a dedicated infrastructure team managing Kubernetes clusters, patching Linux servers, or debugging networking issues. Azure's Platform-as-a-Service offerings let us focus on building product while Microsoft handles the infrastructure.

Our architecture uses:

Why Not AWS or GCP?

Honest answer: all three major cloud providers are excellent, and you can build great products on any of them. We chose Azure because of its tight integration with .NET (unsurprising, given Microsoft builds both), the quality of its PaaS offerings for our specific architecture, and the fact that Azure has data centres in India (Central India and South India regions), which means lower latency for our users.

Azure's pricing for our workload profile — a managed database, a couple of app services, blob storage, and a static web app — is also very competitive. For a bootstrapped product company, cost predictability matters.

The Database: SQL Server

We use Azure SQL Database, which is managed SQL Server in the cloud. For a practice management platform dealing with financial data, a relational database was the obvious choice.

CA firm data is inherently relational. A client has multiple engagements. Each engagement has multiple tasks. Each task has assignments, deadlines, and status updates. Invoices link to clients, services, and tax calculations. This is a domain where foreign keys, transactions, and referential integrity are not optional luxuries — they are requirements.

We considered PostgreSQL (and it would have worked fine), but SQL Server's integration with Entity Framework Core is the most mature, Azure SQL's managed offering is excellent, and our team has deep SQL Server expertise. Sometimes the best technology choice is the one your team knows cold.

We do not choose technologies to be interesting. We choose technologies to be reliable. Our users are running their businesses on our platform — they do not care what database we use, they care that their data is always there when they need it.

Authentication and Authorization

Security is not a feature we add later — it is baked into every layer of the system.

JWT-Based Authentication

CAPilot uses JSON Web Tokens (JWT) for authentication. When a user logs in with their email and password, the server validates credentials, generates a signed JWT containing the user's identity and roles, and returns it to the client. Every subsequent API request includes this token, and the server validates it without needing a database lookup for each request.

We use short-lived access tokens (15 minutes) combined with longer-lived refresh tokens stored in HttpOnly cookies. This means that even if an access token is somehow intercepted, the window of exposure is small. And because refresh tokens are HttpOnly, they are not accessible to JavaScript — mitigating XSS-based token theft.

Role-Based Access Control

CA firms have clear hierarchies — partners, managers, senior associates, article clerks. Not everyone should have access to everything. CAPilot implements role-based access control (RBAC) at both the API level and the UI level:

CI/CD: GitHub Actions to Azure

Our deployment pipeline is fully automated using GitHub Actions. Here is how a code change goes from a developer's machine to production:

  1. Developer pushes to a feature branch — automated checks run: TypeScript compilation, ESLint, unit tests, .NET build, and API tests.
  2. Pull request is created — the PR triggers a preview deployment. Reviewers can test the actual running application, not just read code diffs.
  3. Code review and approval — at least one team member reviews the PR. We use GitHub's CODEOWNERS to ensure changes to critical paths (authentication, billing, data models) require senior review.
  4. Merge to main — triggers the production deployment pipeline. The frontend is built and deployed to Azure Static Web Apps. The backend is built, tested, and deployed to Azure App Service using deployment slots.
  5. Health checks — after deployment, automated health checks verify the application is responding correctly. If health checks fail, the deployment is automatically rolled back.

This entire pipeline runs in under 8 minutes. A developer can merge a PR and see their change live in production before their coffee gets cold.

Security-First Approach

When you are handling financial data for CA firms, security is not something you bolt on — it has to be part of the architecture from day one.

Transport Security

Every connection to CAPilot is HTTPS. There is no HTTP endpoint. We use HSTS headers to ensure browsers never downgrade to unencrypted connections. Azure Static Web Apps and App Service both enforce TLS 1.2 minimum.

Content Security Policy

Our frontend sends strict Content Security Policy (CSP) headers that prevent inline scripts, restrict which domains can serve resources, and block common XSS attack vectors. We also set X-Frame-Options: DENY to prevent clickjacking and X-Content-Type-Options: nosniff to prevent MIME-type sniffing attacks.

Input Validation

Every piece of data that enters our system through the API is validated using FluentValidation rules. We validate not just types and lengths, but business rules — a GST number must match the expected format, a PAN must be exactly 10 characters in the correct pattern, invoice amounts must be non-negative. Invalid data is rejected before it ever reaches the business logic layer.

Data Encryption

Data is encrypted at rest using Azure's built-in encryption (AES-256) and in transit using TLS. Sensitive fields like API keys and connection strings are stored in Azure Key Vault, not in configuration files or environment variables that could be accidentally exposed.

Code Quality Practices

Technology choices are only half the story. How you write code matters just as much as what you write it in.

Code Reviews

Every change to the CAPilot codebase goes through a pull request. No exceptions. Even the founder's code gets reviewed. This is not about gatekeeping — it is about catching bugs, sharing knowledge, and maintaining consistency. Our PR template includes sections for: what changed, why it changed, how to test it, and any deployment considerations.

Testing Strategy

We use a pragmatic testing approach:

Structured Logging with Serilog

Every API request, every database query, every error is logged in a structured format using Serilog. Logs include correlation IDs so we can trace a single user action across multiple services. When something goes wrong in production, we can search logs by user, by endpoint, by error type, and reconstruct exactly what happened.

Monitoring and Observability

You cannot fix what you cannot see. We use Azure Application Insights for real-time monitoring of both the frontend and backend:

How This Stack Enables Rapid Iteration

The real test of a tech stack is not how it looks on paper — it is how fast you can ship. Here is what our stack enables in practice:

This speed is not about cutting corners. It is about choosing tools that work well together, automating everything that can be automated, and spending engineering time on product features instead of infrastructure plumbing.

What We Would Do Differently

No tech stack is perfect, and honesty matters. Here are a few things we have learned:

These are solvable problems, and we are solving them. The core architecture — React, .NET, Azure, SQL Server — has proven itself solid.

Wrapping Up

Technology choices are not about following trends or impressing other engineers. They are about building a foundation that lets you serve your users reliably, ship features quickly, and scale when growth demands it.

For CAPilot, React + TypeScript gives us a fast, type-safe frontend. .NET 8 gives us a performant, enterprise-ready backend. Azure gives us managed infrastructure that a small team can operate confidently. And GitHub Actions ties it all together with automated testing and deployment.

If you are building a SaaS product and evaluating your own stack, I hope this gives you a useful reference point. And if you are a CA firm wondering what is under the hood of the software you are trusting with your practice data — now you know.