Languages
C#
A strongly-typed, modern language on the .NET runtime — used by engineers who run the services they ship.
Overview
C# is a strongly-typed, multi-paradigm language that runs on the .NET runtime. It began life in 2000 as Microsoft’s answer to Java and has, over two decades and a dozen major versions, become one of the most capable general-purpose languages in wide use — object-oriented at its core, but comfortable with functional style, and increasingly expressive with each release. Worth stating plainly, because the two are constantly confused: C# is the language, and .NET is the platform it runs on — the runtime, the garbage collector, the standard libraries and the tooling. You write C#; you deploy on .NET. Most of what people credit to one actually belongs to the other.
The language is memory-managed: a garbage collector reclaims memory for you, so whole classes of manual-memory bugs simply do not exist, at the cost of giving up the deterministic control you would get from Rust or C++. C# has also been a genuine originator of ideas rather than a follower. LINQ brought first-class, composable querying into the language years before it was fashionable elsewhere; async/await — now copied by nearly every mainstream language — was pioneered here. More recent versions add records, exhaustive pattern matching, nullable reference types that push null-safety into the compiler, and spans for allocation-free work over memory. It is a language that has kept moving.
We reach for C# when a system needs to be correct, long-lived and maintained by a team — enterprise back-ends on ASP.NET Core, internal line-of-business tools, service layers, and the occasional Unity game or desktop app. The single most important thing to understand in 2026 is that C# is no longer a Windows-only, Microsoft-only proposition. Since .NET Core and the unification at .NET 5, it is genuinely cross-platform: we build, test and run C# services in Linux containers on Kubernetes every day, and the old perception that C# means Windows Server and licence fees is simply out of date. We are equally blunt about where it does not belong, which we get into below.
Best for — Long-lived, correctness-sensitive back-end systems and internal tools — where a strong type system, a mature runtime and a team fluent in .NET compound into real maintainability.
Why teams choose C#
The compiler is your first reviewer
Static typing, nullable reference types and exhaustive pattern matching turn a large category of runtime failures into compile-time errors. Whole bugs — null dereferences, unhandled cases, type mismatches — are caught before code ever runs, which matters most on the systems that live for years.
A mature runtime and standard library
Two decades of investment mean the batteries are genuinely included: collections, async I/O, JSON, HTTP, cryptography and data access are first-party, well-documented and stable. You assemble far less from third-party packages than in younger ecosystems, and what you do assemble is better vetted.
Cross-platform without a rewrite
The same C# codebase builds and runs on Linux, Windows and macOS. We deploy .NET services as small Linux container images and run them on Kubernetes alongside everything else — no Windows licences, no special hosting, none of the old constraints.
Why businesses choose C#
- You are building software meant to last, and you value a compiler that catches mistakes over the freedom of a dynamic language that lets them through to production.
- Your team already works in .NET, or you want to standardise on a mature, well-supported platform with dependable releases rather than chasing the language of the month.
- You need a back-end that performs well under real load and deploys as an ordinary Linux container, not a special Windows-shaped exception in your infrastructure.
- You want the option of one language across server, desktop and — through Unity — interactive 3D, so skills and patterns carry across surfaces instead of fragmenting.
What we build with C#
The capabilities this technology is genuinely strong at — and what we most often build with it.
LINQ
Language-Integrated Query lets you filter, project and aggregate collections, database rows and other sources with the same composable, readable syntax. It reads like intent rather than plumbing, and against a database through Entity Framework it compiles to SQL — one mental model for querying in memory and querying storage.
async/await
C# introduced async/await to the mainstream, and it remains the cleanest model for concurrency in the language. Asynchronous I/O reads like straight-line code while the runtime frees the thread during waits, so a service handles far more concurrent requests without a thread pool exhausted by blocking calls.
Records and pattern matching
Records give concise, immutable data types with value equality for free — ideal for DTOs, domain values and messages. Paired with exhaustive pattern matching and switch expressions, they make modelling and branching on data both terse and safe, with the compiler flagging cases you forgot to handle.
Nullable reference types
Turned on, the compiler tracks which references may be null and warns before a NullReferenceException can ever be thrown. We enable this on new code as a matter of course; it removes the single most common runtime failure in most codebases by making nullability part of the type, not a hope.
Spans and allocation-free memory
Span and Memory give safe, bounds-checked views over slices of memory without copying or allocating. On the hot paths that actually matter — parsing, serialisation, buffer handling — they cut garbage-collector pressure sharply, letting C# get close to systems-language throughput where it counts.
ASP.NET Core
The web framework we build most C# back-ends on: minimal APIs or controllers, built-in dependency injection, model binding and validation, middleware, and first-class support for gRPC, SignalR and health checks. It is fast, cross-platform, and one of the more thoroughly benchmarked server stacks in existence.
Use cases
Enterprise back-ends and APIs
ASP.NET Core services behind web and mobile front ends, and the internal APIs that stitch a business together — the systems where correctness, clear domain modelling and years of maintenance are the whole point.
Line-of-business tools
The workflow systems, admin portals and integrations a business runs on. C#’s type safety and mature data access make these robust to build and, more importantly, safe for the next engineer to change.
Games and interactive 3D
Unity uses C# as its scripting language, which puts C# behind a large share of the world’s games and a growing amount of simulation, visualisation and real-time 3D work outside entertainment.
Desktop applications
Windows desktop software via WPF or WinUI, and increasingly cross-platform desktop through .NET MAUI — for the tools and internal applications that still genuinely belong on the desktop rather than the browser.
When C# is the right choice
- Right when you are building a serious, long-lived back-end — an API, a service layer, a line-of-business system — where the compiler catching mistakes and a mature standard library pay for themselves many times over the life of the product.
- Right when the team already knows C# or the wider .NET ecosystem. The productivity of a team fluent in a language and its tooling almost always outweighs the theoretical merits of a language nobody on the project has shipped.
- Right when you are writing a game or interactive 3D application in Unity, where C# is the scripting language and there is effectively no argument to be had.
- Wrong for quick scripting, glue code and one-off automation. C# needs a project, a build and a runtime; for a fifty-line task, Python or a shell script will be written and forgotten before a C# project has finished scaffolding.
- Wrong when you are firmly inside another ecosystem — a shop whose people, libraries and operational muscle are all Node, Go or Python. C# is an excellent language, but it is not worth importing a whole runtime, toolchain and skillset your team does not have just to gain a stronger type system.
C#: pros and cons
Strengths
- A powerful, modern type system — nullable reference types, records, generics and pattern matching — that pushes errors from runtime to compile time.
- Excellent tooling: Visual Studio, VS Code with the C# Dev Kit, and the dotnet CLI give first-class debugging, profiling and refactoring that few ecosystems match.
- Genuinely cross-platform and container-friendly since .NET 5, with strong performance and a runtime that has been tuned hard for server workloads.
- A large, stable ecosystem and hiring pool, backed by long-term support releases and a company with a clear, dependable release cadence.
Trade-offs
- The historic Windows-and-Microsoft association lingers in people’s heads long after it stopped being true, and it still colours build-versus-buy conversations that should have moved on.
- Heavier than Go or Node for small services: a runtime, a larger base image and more ceremony mean it is not the lightest thing to stand up a tiny endpoint.
- Poorly suited to quick scripting and glue work — the project-and-build model that helps large systems is friction for a throwaway task.
- Outside its own ecosystem it is rarely the natural default, and some of the best libraries in a given niche live in the Python, JavaScript or Rust worlds instead.
Architecture
We treat a C# service as a layered thing with the domain at its centre: the business rules and types that make the system what it is, expressed in plain C# with no framework leaking in, surrounded by thinner layers for application logic, data access and the web edge. ASP.NET Core’s built-in dependency injection is the seam that holds this together — dependencies are declared as interfaces and supplied by the container, so the domain never reaches out to a database or an HTTP client directly. That is what keeps the interesting code unit-testable and the framework replaceable.
We are deliberate about not over-engineering it. Not every service needs full clean architecture, a mediator and five projects; a small API is often best as a handful of files with minimal APIs and Entity Framework, and pretending otherwise just adds ceremony. The judgement is knowing which system is which. Records and nullable reference types let us model the domain precisely — states that should be impossible are made unrepresentable in the type system — so a large share of what would be defensive runtime checks in a looser language is simply enforced by the compiler instead.
Performance
Modern .NET is fast. The just-in-time compiler and a garbage collector tuned hard for server workloads mean an ASP.NET Core service comfortably handles high request throughput, and the framework consistently sits near the top of independent server benchmarks. For the overwhelming majority of back-ends, C# is quick enough that the database and the network are the bottleneck long before the language is — and we profile to prove that rather than assuming it.
Where a hot path genuinely matters, the language gives real tools: spans and Memory to work over buffers without allocating, pooled objects to relieve GC pressure, and, in the extreme, ahead-of-time compilation for faster startup and smaller footprints. We are honest about the trade-off the garbage collector represents — you get memory safety and productivity, and you give up the deterministic, allocation-level control of Rust or C++. For a service that is right; for a hard-real-time or ultra-low-latency system, it may not be, and we will say so.
Security
A managed runtime removes an entire family of vulnerabilities before you write a line: no manual memory management means no buffer overflows or use-after-free, and the type system closes off many mistakes that become security holes in unmanaged code. On top of that, .NET ships mature, first-party security primitives — ASP.NET Core Identity, data protection APIs, well-maintained cryptography, and built-in support for JWT, OAuth and OpenID Connect — so authentication and authorisation are configured from vetted components rather than hand-rolled.
The runtime does not excuse the fundamentals, and we do not let it. Every input is validated at the trust boundary; parameterised queries and Entity Framework close off SQL injection by default; secrets live in a secrets manager or Azure Key Vault, never in source or config committed to a repository. We keep the dependency tree lean and scanned, patch on the long-term-support cadence, and treat authorisation as something enforced on the server for every request rather than assumed because the UI hid a button.
Scalability
We design C# services to scale horizontally, which means keeping them stateless: no session or user state held in a process, so any instance can serve any request and you grow by adding replicas behind a load balancer. Shared state that must persist lives in the database or in Redis, not in memory. This is ordinary discipline, but it is the difference between a service you can scale by changing a number and one you have to re-architect under pressure.
Because .NET builds to small, efficient Linux containers, those replicas run comfortably on Kubernetes and scale with demand like any other workload — there is nothing Windows-shaped to accommodate. async/await is doing quiet work underneath all of this: by never blocking a thread while waiting on I/O, a single instance absorbs far more concurrent connections before it needs a sibling. When a system outgrows a single service, C# and ASP.NET Core sit naturally in a wider architecture, speaking gRPC or messaging to the rest of the estate rather than assuming everything else is also .NET.
C# integrations & ecosystem
The technologies we most often pair with it — each links to how we work with it.
How we work
We start by modelling the domain in the type system, because in C# that is where the leverage is: records, enums and nullable reference types let us make illegal states unrepresentable, so the compiler enforces rules we would otherwise write and re-write as runtime checks. From there we build in thin vertical slices — a real endpoint, wired through to storage, running in a container — rather than scaffolding every layer before anything works. We enable nullable reference types and treat warnings as errors on new code from day one; retrofitting that discipline later is far more expensive than living with it from the start.
The engineers who design the service are the ones who write it and keep it running. That is what we mean by operating what we build: the person choosing between a minimal API and full clean architecture is the person who will be paged if the choice was wrong, so we favour the simplest design that fits and resist ceremony for its own sake. You get typed, tested code on a supported .NET release, and a back-end your own team can read, extend and own.
The service behind it
Delivered throughCustom Software DevelopmentWhat we build with C#
The disciplines this technology most often shows up in — from a first build to taking over and stabilising an existing one.
How we deliver
- 01
Discover
We map the system, the constraints and the business it serves — including the parts nobody documented.
Architecture brief
- 02
Architect
Decisions get made, written down and defended before a line of production code exists.
Decision records
- 03
Build
Short cycles against working software. You see progress in the product, not in a status deck.
Shipping increments
- 04
Operate
Monitoring, incident response and iteration. The system is alive, so the engagement is too.
Runbooks & SLOs
Industries we use C# in
Domain knowledge changes what gets built. A few of the sectors we know before the first meeting.
Also in Languages
Why teams choose us for C#
Senior engineers only
The judgement calls in a C# codebase — how much architecture a service actually needs, where to model with records versus classes, when a hot path justifies spans — are made by people who have made them before and lived with the results. No juniors learning on your system.
We operate what we build
We run the services we ship, so we design for the maintenance reality: supported .NET releases, containers that deploy like everything else, and code the next engineer can read. We optimise for the eighteenth month, not the demo.
Modern .NET, not legacy habits
We build cross-platform on current .NET and deploy to Linux containers as standard. We are not carrying forward Windows-only assumptions from a decade ago, and we will happily lift a legacy .NET Framework app onto modern .NET if that is what you actually need.
Honest about when not to use C#
If your task is really a script, or your team lives in another ecosystem, we will tell you before you commit to a runtime you do not need. We would rather point you at Python or Go than sell you a .NET project that does not fit.
Typical timeline
- 01
Discovery and domain modelling
One to two weeks understanding the domain, the integrations and the constraints, and settling the architecture — how layered, which framework features, where the boundaries sit — before code volume grows.
- 02
First vertical slice
Two to three weeks delivering one real feature end to end — endpoint through to storage, running in a container — proving the design against reality rather than a diagram.
- 03
Iterative build
Feature-by-feature delivery in short cycles, each slice deployable, with tests on the load-bearing paths and performance checked as we go rather than bolted on at the end.
- 04
Hardening and handover
Profiling under realistic load, security review, and documentation so your team can run and extend the service on a supported .NET release without us in the room.
How pricing works
- Fixed-scope builds for well-defined systems — an API, a service, an internal tool — quoted once the domain and integrations are understood.
- Monthly senior engagement for ongoing product work, where scope evolves and you want continuity of the people who know the codebase rather than a fixed deliverable.
- Audits and rescues of existing .NET codebases — a stalled project, a performance problem, a framework upgrade off end-of-life .NET — priced by the assessment.
- Upgrade and migration work, typically moving legacy .NET Framework applications onto modern, cross-platform .NET, scoped after we have seen what is actually there.
Hire C# engineers
Need C# capacity on your own team? We embed named senior engineers into your existing team — reporting to your leads, working in your rituals — so you add capacity without a hiring cycle.
Hire C# engineersCommon questions
What is the difference between C# and .NET?
C# is the language — the syntax, the type system, features like LINQ and async/await. .NET is the platform it runs on: the runtime, the garbage collector, the standard libraries and the tooling. You write C# and deploy on .NET. The two get conflated constantly, but the distinction matters, because much of what people credit to “C#” — the cross-platform runtime, the performance, the container support — actually belongs to .NET.
Is C# still tied to Windows and Microsoft?
No, and this is the most out-of-date belief about the language. Since .NET Core and the unification at .NET 5, C# is genuinely cross-platform: we build, test and run C# services in Linux containers on Kubernetes as a matter of routine, with no Windows licences involved. The perception lingers because C# was Windows-only for its first fifteen years, but that has not been the reality for a long time now.
Should we use C# for small services or scripts?
Often not. C# needs a project, a build and a runtime, which is friction for a fifty-line script or a tiny endpoint — Python or Go will be lighter and quicker to stand up. C# earns its place on systems meant to last, where the type system and mature libraries pay off over years of maintenance. If your task is really glue or automation, we will say so rather than reach for .NET out of habit.
How does C# performance compare to Go or Node?
Modern .NET is fast and consistently sits near the top of independent server benchmarks, comfortably ahead of Node for CPU-bound work and competitive with Go for most server workloads. The honest trade-off is weight, not speed: C# carries a heavier runtime and larger base image than Go, so for a very small service Go may deploy leaner. For a substantial back-end, the runtime cost is noise against the value of the ecosystem and type system.
Can we build games with C#?
Yes — Unity uses C# as its scripting language, which puts C# behind a large share of the world’s games and a great deal of simulation, visualisation and real-time 3D work beyond entertainment. It is one of the clearest cases where C# is simply the right and expected choice. Note that game work in Unity is a different discipline from the back-end and service engineering that is our core, and we are candid about where our strengths lie.
Building on C#?
A technical conversation with the engineers who would do the work. If we are not the right fit, we will say so on the call.