launchthat
.NET vs Convex: When to Use a Traditional Backend vs a Reactive Platform
Both .NET and Convex can power production backends. After building multi-tenant SaaS platforms, high-performance APIs, and real-time dashboards across both, here is how I decide which one fits — and when the answer is both.
I have built production systems on both .NET and Convex. AtlasOps is a multi-tenant SaaS control center running ASP.NET Core with EF Core, PostgreSQL, and Redis. PulseAPI is a high-performance API service with benchmark-driven p95/p99 optimization on ASP.NET Core with Dapper. Portal, LaunchThatBot, and TraderLaunchpad all run on Convex with real-time subscriptions, scheduled functions, and file storage.
These are not toy projects. They handle tenant isolation, billing webhooks, sub-50ms API latencies, live trading data, and 34-plugin architectures in production.
Choosing between .NET and Convex is not about which is "better." It is about which architecture fits the problem. They solve fundamentally different categories of problems, and after building extensively with both, I have a clear decision framework for when to reach for each one.
The mental models
.NET is a general-purpose application runtime. You write C# (or F#), compile it, and run it on any infrastructure — bare metal, VMs, containers, Kubernetes, Azure App Service, or a Raspberry Pi. The framework gives you HTTP routing, dependency injection, middleware pipelines, and an ORM. You bring your own database, your own caching layer, your own message queue, your own real-time infrastructure. The flexibility is the value.
Convex is an integrated application backend. Your code runs as TypeScript queries, mutations, and actions against a built-in transactional document database with automatic real-time subscriptions. The database is not an add-on — it is the foundation. Scheduling, file storage, auth, and search are first-party primitives. The integration is the value.
The simplest way to think about it: .NET gives you a powerful engine and lets you build the car. Convex gives you a car and lets you drive.
Data modeling: relational vs document
This is where the two platforms diverge most sharply, and it is usually the deciding factor.
ASP.NET Core with Entity Framework:
public class Tenant
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Subdomain { get; set; }
public SubscriptionPlan Plan { get; set; }
public ICollection<TenantUser> Users { get; set; }
public ICollection<AuditEntry> AuditLog { get; set; }
}
public class TenantUser
{
public Guid TenantId { get; set; }
public Guid UserId { get; set; }
public TenantRole Role { get; set; }
public Tenant Tenant { get; set; }
public User User { get; set; }
}
Entity Framework gives you navigation properties, lazy/eager loading strategies, complex joins, window functions, CTEs, stored procedures, views, and migrations. If your domain model has 50+ tables with deep relational semantics — foreign keys, many-to-many relationships, composite indexes, cascading deletes — a relational ORM is the right tool.
Convex schema:
portfolioProjects: defineTable({
slug: v.string(),
title: v.string(),
description: v.string(),
skills: v.array(v.string()),
tags: v.array(v.string()),
relatedProjects: v.array(v.string()),
featuredImageStorageId: v.optional(v.id("_storage")),
sortOrder: v.number(),
publicationStatus: publicationStatusValidator,
})
.index("by_slug", ["slug"])
.index("by_publicationStatus_and_sortOrder", [
"publicationStatus", "sortOrder",
]),
Convex schemas are flat and document-oriented. Relationships are expressed through ID references and array fields, not join tables. You do not have cascading deletes, foreign key constraints, or navigation properties. Instead, you have automatic real-time subscriptions on every query, ACID transactions on every mutation, and type safety from database to client with zero additional configuration.
The trade-off: If your data model is heavily relational with complex reporting queries — revenue by tenant by month with window functions, user activity cohort analysis, inventory movement across warehouses with recursive CTEs — a relational database with EF Core or Dapper gives you the query expressiveness you need. If your data model is application-centric with mostly lookup-by-key, list-with-filter, and real-time-update patterns, Convex's document model is simpler and faster to build on.
Real-time: bolted on vs built in
This is where Convex's architecture makes the strongest case.
ASP.NET Core with SignalR:
public class DashboardHub : Hub
{
public async Task JoinTenantGroup(string tenantId)
{
await Groups.AddToGroupAsync(Context.ConnectionId, tenantId);
}
}
// In your mutation handler, after the database write:
await _hubContext.Clients.Group(tenantId)
.SendAsync("PriceUpdated", newPrice);
SignalR works. I have used it in production. But you are responsible for connection lifecycle management, group membership, reconnection handling, backpressure, and — critically — cache invalidation. When you write to the database, you must explicitly push updates to the right clients. If you miss a notification path, clients see stale data. If the SignalR server restarts, clients must reconnect and you must decide whether to replay missed events or force a full refetch.
Convex subscriptions:
const prices = useQuery(api.prices.list, { symbol: "AAPL" });
That is the entire real-time implementation. The prices variable updates automatically whenever the underlying data changes. There is no hub to configure, no group to join, no explicit notification to send. The reactivity is built into the query layer. When a mutation writes new data, every connected client subscribed to an affected query receives the update within milliseconds.
The difference is not incremental — it is architectural. In .NET, real-time is a layer you add on top of your request/response model. In Convex, real-time is the model.
Performance-critical workloads
This is where .NET has a clear advantage.
ASP.NET Core runs compiled C# on the CoreCLR runtime. It has predictable memory allocation, value types for zero-allocation hot paths, Span<T> for buffer manipulation without copies, and access to the full .NET standard library. For CPU-intensive operations — batch data processing, image manipulation, ML inference, cryptographic operations — the performance ceiling is significantly higher than a JavaScript runtime.
PulseAPI uses Dapper for performance-critical query paths alongside EF Core for domain modeling. The hybrid approach gives us both developer productivity and fine-grained control over SQL generation, parameter binding, and result mapping. We run k6 load test suites to baseline and validate every optimization. That kind of benchmark-driven tuning is natural in .NET because the runtime gives you the profiling tools and allocation control to actually act on what the benchmarks reveal.
Convex functions run in a JavaScript/TypeScript runtime with execution time limits. They are optimized for transactional CRUD workloads — reads, writes, and subscriptions — not sustained compute. If your hot path involves processing a 10MB CSV, running 10,000 regex matches, or computing financial aggregates across millions of rows, you will hit Convex's function limits before you hit the performance you need.
The escape hatch: Convex actions with "use node" can call out to external services for heavy compute. You can run the CPU-intensive work in a Node.js environment or call an external .NET microservice. But if most of your backend is compute-heavy, you are fighting the platform instead of leveraging it.
The infrastructure question
.NET self-hosting is battle-tested across every deployment model: IIS on Windows Server, Kestrel in Docker containers, Kubernetes with Helm charts, Azure App Service, AWS ECS, bare metal with systemd. I have deployed .NET applications to all of these. The operational maturity is decades deep. You can run .NET in air-gapped networks, on classified infrastructure, behind corporate firewalls with no internet access.
Convex self-hosting is real but young. The open-source Convex backend can run on your own infrastructure. But the operational story — monitoring, backup strategies, upgrade paths, high availability — does not have the same depth of community knowledge and battle-tested patterns that .NET has accumulated over 20+ years.
For regulated environments — healthcare (HIPAA), finance (SOX/PCI-DSS), government (FedRAMP, IL4+) — .NET's compliance certification history and enterprise support contracts are often a hard requirement. It is not that Convex cannot be made compliant. It is that the compliance team has already approved .NET and they are not re-evaluating.
Developer experience and velocity
For application backends — the kind where you are building CRUD operations, real-time dashboards, form submissions, and webhook handlers — Convex's developer experience is measurably faster.
A typical .NET feature implementation:
- Add migration for new table or columns
- Update EF Core model and DbContext
- Write repository or service layer
- Write controller with request/response DTOs
- Add validation with FluentValidation or data annotations
- Wire up dependency injection
- Add SignalR notification if real-time is needed
- Write integration tests against test database
- Run migration in staging, verify, then production
The same feature in Convex:
- Update schema.ts
- Write query or mutation with inline validators
- Use it from the client
Steps 4 through 9 from the .NET list do not exist. There is no API layer to maintain because queries and mutations are the API. There is no ORM configuration because the database is built in. There is no separate validation library because validators are part of the function definition. There is no real-time setup because every query is already reactive.
The velocity difference compounds. Over a month of feature work, the .NET project accumulates hundreds of files across controllers, services, repositories, DTOs, validators, and migrations. The Convex project has a convex/ directory with schema and functions. Both ship the same features to users.
Team and organizational factors
This is the dimension that engineers underestimate and managers overweight — and both are partially right.
Choose .NET when:
- Your team has 10 years of C# experience and zero TypeScript experience. Retraining costs are real and the team will be slower for months before they are faster.
- You need to hire from the enterprise .NET talent pool. In many markets, senior C# developers are more available than senior TypeScript backend developers.
- The organization has existing investments in Azure, SQL Server, Active Directory, and Visual Studio Enterprise. The tooling integration compounds across the stack.
- Multiple teams need to work on the backend simultaneously. .NET's project/solution structure, namespaces, and assembly boundaries provide natural team ownership boundaries that Convex's flat
convex/directory does not.
Choose Convex when:
- Your team is already proficient in TypeScript and React. Convex's learning curve is near zero for this profile.
- You are a solo developer or small team where velocity matters more than organizational structure.
- You want to eliminate the "API layer tax" — the ongoing cost of maintaining controllers, DTOs, serializers, and versioning between frontend and backend.
- Real-time features are core to the product, not a nice-to-have bolted on later.
When to use both
The most interesting architecture is the one where both coexist.
I run this pattern in production: Convex handles the real-time application layer — live dashboards, collaborative features, instant UI updates, webhook ingestion, scheduled jobs. A .NET service handles the compute-heavy backend — batch processing, complex reporting queries, ETL pipelines, integrations with enterprise systems that speak SOAP and WCF.
The boundary is clean:
- Convex owns the user-facing data layer: queries, mutations, subscriptions, auth, file storage.
- .NET owns the processing layer: heavy computation, complex SQL analytics, legacy system integration.
- Convex actions call the .NET service for compute-intensive operations and write results back to Convex for real-time propagation to clients.
This gives you the best of both: Convex's real-time reactivity and developer velocity for the application layer, and .NET's performance ceiling and ecosystem depth for the infrastructure layer.
The decision matrix
| Factor | .NET wins | Convex wins |
|---|---|---|
| Data model complexity | 50+ tables, deep relational semantics | Document-oriented, lookup-and-list patterns |
| Real-time requirements | Not needed or limited to notifications | Core feature, every query should be live |
| Compute intensity | CPU-heavy batch processing, ML, analytics | Transactional CRUD, webhooks, scheduling |
| Team expertise | C# / enterprise .NET background | TypeScript / React background |
| Compliance requirements | Regulated industries with established .NET approval | Startups and products without compliance overhead |
| Infrastructure control | Air-gapped, on-prem, custom deployment | Managed infrastructure, zero-ops preference |
| Development velocity | Large teams with clear domain boundaries | Small teams prioritizing feature shipping speed |
| Existing ecosystem | Azure, SQL Server, Active Directory | Modern web stack, Vercel, edge deployment |
It is not about legacy
The common framing — "use .NET only if you have legacy code you cannot rewrite" — misses the point entirely. .NET is not a legacy platform. ASP.NET Core is a modern, high-performance framework that outperforms most alternatives in raw throughput benchmarks. Entity Framework Core is a capable ORM with excellent migration tooling. The .NET ecosystem is actively evolving with each annual release.
The real question is not "old vs new." It is "what kind of problem are you solving?"
If the problem is "build an application backend with real-time features, type-safe client integration, and minimal infrastructure overhead," Convex solves it faster and with less operational burden than .NET.
If the problem is "build a high-performance API with complex relational queries, fine-grained runtime control, and deployment to regulated infrastructure," .NET gives you capabilities that Convex does not.
And if the problem is "build a product that needs both" — as most ambitious products eventually do — the two platforms compose cleanly together.
Want to see how this was built?
See AtlasOps (.NET) and Portal (Convex) in the project galleryWant to see how this was built?
Browse all posts