Home › Programming languages › Choosing
guide low

Choosing a language

Problem Which programming language should you use for a given job, and when is a rewrite or a mix of languages worthwhile? This guide compares languages by speed, memory, hiring and build cost.

The master decision table: which language for which job, what it costs in speed, memory, hiring and build pain, and when to mix them.

languagesdecision-guideperformanceproductivityecosystem
Overview

Language choice is mostly an ecosystem and team choice: the libraries you need, the runtime you deploy, the people who maintain it. Raw speed matters for a few jobs (engines, databases, games, inference); for most services the database and network dominate. Pick the language whose ecosystem solves your hardest problem; drop to a faster one only for the measured hot spot.

Key facts

Use when

  • Starting a project or service, or judging a rewrite.
  • Real choices by field, from the language pages: CDN proxies (Rust at Cloudflare), payments (Go at PayPal and American Express), telecoms and banking (Erlang), games (C# in Unity), scientific computing (Python and NumPy), mobile (Kotlin on Android).

Avoid when

  • The team already ships well in a "fast enough" language: rewrites rarely pay off.

Deep dive

Decision table

JobPickWhyRunner-up
Web/API backend, typical CRUDGo, TypeScript (Node), Kotlin/Java, C#Productive, mature HTTP/DB stacks, easy hiringPython (Django/FastAPI)
Backend with hard latency/throughput targetsRustNo GC pauses, predictable memory, async I/OGo, C#
Database, storage engine, proxy, search engineRust or C++Control of layout, allocation, I/OZig, Go (if p99 GC pauses are acceptable)
Game engine, real-time audio, HFTC++Ecosystem (Unreal, SDKs), toolchains, talentRust, Zig
Game logic on an engineC# (Unity, Godot), C++/Blueprints (Unreal), GDScriptThe engine decides
Multiplayer game serverRust, C#, Go, C++Tick loops need low jitter; share code with client if possibleErlang/Elixir for lobbies/chat
ML training, research, data sciencePythonPyTorch/JAX/NumPy; kernels underneath are C++/CUDAJulia
Custom GPU kernelsCUDA C++ or TritonBest tooling and libraries on NVIDIAHIP (AMD), Metal (Apple)
Model inference servingPython (vLLM, SGLang) or C++/Rust runtimesPython orchestrates, C++/CUDA computesRust for the serving shell
CLI toolsGo or RustSingle static binary, fast startupPython with uv, Zig
Browser frontendTypeScriptOnly first-class option; WASM for hot loopsRust → WASM for compute
Mobile appsSwift (iOS), Kotlin (Android)Platform APIs first-classDart/Flutter, React Native, KMP for shared code
Desktop appsPlatform native, or TypeScript + Electron/TauriReuse web skillsC#/.NET (Windows), Qt (C++)
Chat, presence, millions of connections, telecomElixir/ErlangCheap processes, supervision, distributionGo
Embedded, microcontrollersC, Rust (embedded-hal, Embassy)Vendor SDKs are C; Rust where HALs existZig, C++
OS kernels, driversC, Rust (Linux, Windows, Android drivers)Kernel ABI and toolingC++ (Windows), Zig
Data pipelines, analyticsSQL + PythonLet the engine (DuckDB, Postgres, Spark) do the workScala/Java on Spark
Glue, scripting, automationPython, shell for < 50 linesFastest to writeTypeScript (Deno/Bun)
Enterprise systems, long-lived large codebasesJava/Kotlin, C#Tooling, refactoring, stable runtimesGo
Smart contractsSolidity (EVM), Rust (Solana)The chain decides

Cost model

LanguageCPU (vs C)Memory modelConcurrencyStartupBuild/deploy
Rust~1xOwnership, no GCThreads + async (Tokio)msStatic binary; slow compiles
C/C++1xManual / RAIIThreads, coroutines (C++20)msCMake + package pain
Zig~1xManual, explicit allocatorsThreadsmsEasy cross-compile; pre-1.0 churn
Go~1.5-3xConcurrent GCGoroutines (M:N)msStatic binary, very fast compiles
Java/Kotlin~1-2x after JIT warmupGenerational GC (G1, ZGC)Threads, virtual threads, coroutines100s of ms (native-image: ms)Fat JAR / container
C#~1-2xGenerational GC, value typesasync/await, Tasks100s of ms (NativeAOT: ms)Single-file or AOT binary
TypeScript/JS~2-5xGC (V8)Single-threaded event loop + workers10s of msNode/Bun/Deno, bundlers
Python~10-100x pure PythonRefcount + cycle GCGIL (free-threaded build emerging), asyncio, processes10s of msuv/venv, containers
Erlang/Elixir~3-10xPer-process heaps and GCMillions of preemptive processes100s of msOTP releases

Numbers are order-of-magnitude for CPU-bound code; I/O-bound services see much smaller gaps.

How to decide

  1. List the hardest technical requirement (p99 < 1 ms? GPU kernels? 1M websockets? iOS?). It usually eliminates most options.
  2. Check the ecosystem: is there a mature library for your database, protocol, cloud SDK, auth provider?
  3. Weigh the team: a language nobody on the team knows costs months; hiring markets differ by region.
  4. Prototype the hot path and measure before committing to a "fast" language for everything.
  5. Plan the boundary for mixing: FFI (C ABI), WASM, gRPC between services, or a GPU language under Python.

Code

A typical split: Python orchestration calling a Rust hot loop through PyO3/maturin.

// Cargo.toml: [lib] name = "fastlib", crate-type = ["cdylib"]; pyo3 = { version = "0.22", features = ["extension-module"] }
use pyo3::prelude::*;

/// Count positions where two equal-length byte strings differ (hot loop in Rust).
#[pyfunction]
fn hamming(a: &[u8], b: &[u8]) -> PyResult<usize> {
    if a.len() != b.len() {
        return Err(pyo3::exceptions::PyValueError::new_err("length mismatch"));
    }
    Ok(a.iter().zip(b).filter(|(x, y)| x != y).count())
}

#[pymodule]
fn fastlib(m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(hamming, m)?)?;
    Ok(())
}
uv tool run maturin develop --release   # builds and installs into the active venv
python -c "import fastlib; print(fastlib.hamming(b'abc', b'abd'))"

Efficiency

  • Cost: per-language costs are on each language page; the ones that decide a choice, with their sources: a goroutine starts with a few KB of stack (Go FAQ), an Erlang process uses 327 words, about 2.6 KB (Erlang Efficiency Guide), a CPython int is 28 bytes (measured with sys.getsizeof), Spring PetClinic starts in 4.5 s on JDK 23 and 2.6 s with an AOT cache on JDK 24 (JEP 483), and Wasm ran SPEC CPU 45-55 % slower than native in browsers (Jangda et al., 2019). Bound: usually the database and network, not the language.
  • Levers:
    • profile, then move only the hot function to a faster language — one loop is usually the problem (order of) — Python or JS services with one hot spot
    • batch calls across the language boundary — one call per buffer, not per element (no figure) — PyO3, N-API, Wasm and cgo boundaries
    • ahead-of-time compile for startup (JVM AOT cache, Native AOT, Wasm precompile) — 42 % lower startup on PetClinic (JEP 483) — serverless and CLIs
    • tune the GC instead of leaving it (GOGC, ZGC, MaxRAMPercentage) — halve GC CPU or cut pauses (Go GC guide, JEP 439) — GC'd services with a latency or memory target
    • keep to two to four languages per organization — fewer toolchains to secure and staff (order of) — whole-org decisions
  • Naive → standard → state of the art:
    • rewrite everything in the fastest language · months of work, gain only if CPU-bound
    • profile, then fix the query or loop in the current language · usually enough
    • current language plus a native hot path behind a stable ABI (PyO3, napi-rs, UniFFI) · native speed where it matters

Pitfalls

  • Choosing by benchmark-game numbers for an I/O-bound CRUD service.
  • Choosing by hype for a team that can't support it in production (on-call, debugging, profiling).
  • Rewriting a working system for speed without profiling; usually one query or one loop is the problem.
  • Too many languages in one org: each adds CI, security scanning, libraries and hiring overhead. Two to four is plenty.
  • Ignoring deployment: GC'd runtimes in small containers, JIT warmup in serverless, Python native wheels on unusual platforms.
  • Using dynamic languages for large codebases without type checking (mypy/pyright, TypeScript strict).

Implementations

namelangrepoinstallverdictlicencehealthas_ofnotes
PyO3RustPyO3/pyo3cargo add pyo3————Rust bindings for Python
maturinRustPyO3/maturinpip install maturin————build and publish PyO3 wheels
napi-rsRustnapi-rs/napi-rscargo add napi————Rust addons for Node.js
UniFFIRustmozilla/uniffi-rscargo add uniffi————one Rust core for Kotlin, Swift and Python
rust-bindgenRustrust-lang/rust-bindgencargo add bindgen --build————generate Rust bindings from C headers

Sources

Alternatives and related

RustIs Rust the right language when you need native speed without a garbage collector and without memory-safety bugs? This guide weighs that against its learning curve and compile times.C and C++Is C or C++ the right language for a project? This guide weighs maximum performance and the huge native ecosystem against the memory-safety and undefined-behaviour risks you must manage.ZigIs Zig a suitable C replacement for low-level systems code and cross-compiling, and what does its pre-1.0 status cost? This guide helps decide between Zig, C and Rust.GoIs Go the right language for a network service, proxy or infrastructure tool? This guide covers what it is good at, and where tail latency or heavy numerics call for something else.Java and KotlinIs the JVM, with Java or Kotlin, the right platform for a large long-running backend, data infrastructure or Android app? This guide covers its strengths and where its startup and memory cost hurts.C#Is C# on .NET the right choice for a web API, desktop app or game logic? This guide covers where it fits, its performance characteristics, and where another language is a better pick.PythonIs Python the right language for ML, data work, scripting or a backend, and how do you avoid its slowness? This guide covers where it pays off and where it does not.TypeScript and JavaScriptIs TypeScript or JavaScript the right choice for browser UIs and for server code, and where does its single-threaded model become a problem? This guide helps decide where it fits.SQLHow should engineers approach SQL for business data and analytics? This guide explains why query speed depends on schema and indexes, and where a relational database is a poor fit.CUDA and GPU languagesHow should you program a GPU, and when is it worth writing custom kernels rather than using existing libraries? This guide helps pick between libraries, Triton and CUDA C++ for numeric workloads.Erlang and ElixirIs Erlang or Elixir the right choice for a system that must stay up while serving huge numbers of concurrent connections or sessions, such as chat, messaging or IoT gateways, and where is it a poor fit?