← Back to blog

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.

Apr 6, 2026Desmond Tatilian

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:

  1. Add migration for new table or columns
  2. Update EF Core model and DbContext
  3. Write repository or service layer
  4. Write controller with request/response DTOs
  5. Add validation with FluentValidation or data annotations
  6. Wire up dependency injection
  7. Add SignalR notification if real-time is needed
  8. Write integration tests against test database
  9. Run migration in staging, verify, then production

The same feature in Convex:

  1. Update schema.ts
  2. Write query or mutation with inline validators
  3. 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 winsConvex wins
Data model complexity50+ tables, deep relational semanticsDocument-oriented, lookup-and-list patterns
Real-time requirementsNot needed or limited to notificationsCore feature, every query should be live
Compute intensityCPU-heavy batch processing, ML, analyticsTransactional CRUD, webhooks, scheduling
Team expertiseC# / enterprise .NET backgroundTypeScript / React background
Compliance requirementsRegulated industries with established .NET approvalStartups and products without compliance overhead
Infrastructure controlAir-gapped, on-prem, custom deploymentManaged infrastructure, zero-ops preference
Development velocityLarge teams with clear domain boundariesSmall teams prioritizing feature shipping speed
Existing ecosystemAzure, SQL Server, Active DirectoryModern 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?

Browse all posts