Skip to content

Instantly share code, notes, and snippets.

@arturaz
Last active November 16, 2025 15:01
Show Gist options
  • Select an option

  • Save arturaz/169c19d7c3e77b062834057d96df651a to your computer and use it in GitHub Desktop.

Select an option

Save arturaz/169c19d7c3e77b062834057d96df651a to your computer and use it in GitHub Desktop.
Why Scala

Disclaimer: I use Scala since 2012 and am author of doobie-typesafe and yantl libraries and a contributor to Laminar and Mill build tool. This is also generated by GPT 5 with a prompt tailored from my instructions and reviewed by me.


Short answer: given what you already do (C#, TypeScript, Rust, React, .NET/Express/Axum), I’d seriously pick Scala 3 as your “functional programming language,” not Haskell/Elm/PureScript, and lean on the modern FP ecosystem on top of it.

You get:

  • Pure FP when you want it (Cats Effect / ZIO / Kyo).
  • A “real” industrial ecosystem for web APIs, CLIs, and UIs.
  • One language for JVM backends, Node/browser via Scala.js, and even native.

Below is how that looks in practice.

Why Scala fits your use cases

You want:

  • Web APIs
  • Web UIs
  • CLIs
  • DB access
  • While learning FP properly.

Scala 3 gives you:

  • Single language, three runtimes: JVM, JavaScript (Scala.js), and Native.
  • Strong FP ecosystem – Cats, Cats Effect, ZIO, Kyo, FS2, etc.
  • Industrial-grade HTTP & DB libs – http4s, ZIO HTTP, Tapir, Doobie, etc.
  • An advanced type system with HKTs, typeclass derivation, union/intersection types, implicit parameters (now given/using), opaque types/newtypes, etc.

Compared to:

  • Haskell – fantastic if you want “pure FP lab environment,” but you’ll fight tooling and deployment for common web stacks, plus interop with JS is not first-class.
  • Elm – nice for learning and front-end-only SPAs, but it’s deliberately restrictive and not general-purpose. You’d still need another stack for backend.
  • PureScript – closer to what you want, but yes: you’ll end up with a lot of JS glue and a smaller ecosystem around HTTP, DBs, and infra than on the JVM.

Scala lets you do “Haskell-ish” FP on stacks that look much more like what you already ship.

Backend: APIs, domain code, DB, effects

You can build APIs with a pure FP core and a thin HTTP/DB layer around it.

Effects

Pick one (they’re all good):

  • Cats Effect – the “standard” Typelevel effect runtime, with a huge ecosystem and integrations (http4s, FS2, Tapir, Doobie, etc.).
  • ZIO – batteries-included effect system with its own ecosystem (ZIO HTTP, ZIO Config, ZIO Schema, etc.).
  • Kyo – a newer, multi-effect toolkit that targets JVM, JS, and Native out of the box and aims to unify effects in a more ergonomic way.

If you like Rust’s async + structured concurrency, Cats Effect and ZIO will feel conceptually familiar: pure effect values, fibers, resource safety, etc.

HTTP & APIs

Typical options:

  • http4s + Cats Effect – purely functional HTTP, very close to the metal of FP.
  • ZIO HTTP – HTTP server/client built directly on ZIO, high performance and nice DSL.
  • Cask – small, Flask-style microframework for when you want something dead simple without deep FP machinery.

On top of your HTTP choice, you can define APIs with Tapir:

  • With Tapir, you define endpoints as Scala types, then generate:
    • servers (http4s, ZIO HTTP, Akka, etc.)
    • OpenAPI docs
    • clients.

That’s very close to “type-level description of your API,” which is exactly what FP people brag about.

Database access

For relational DBs:

  • Doobie – a mature, functional JDBC wrapper.
  • doobie-typesafe – an extra layer that gives you typesafe table/column references on top of Doobie, so schema changes show up as compile errors.

This answers your “ecosystem for DB connections” question: it’s solid, battle-tested, and fits the FP style nicely.

Domain modeling: newtypes etc.

This is where you lean on the type system hard:

  • yantl – “Yet Another Newtype Library” for Scala 3, focused on localized error messages, and available on JVM, JS, and Native.

Use it (or similar libraries) to encode domain-specific types: UserId, OrderId, NonEmptyString, etc. This gets you very close to the “Haskell newtype” feel, but in Scala.

Combine that with derivation (auto-deriving typeclass instances for codecs, configs, etc.), HKTs, and implicits/givens to build a strongly-typed domain model that still composes.

Frontend: Scala.js instead of TypeScript

Scala.js compiles Scala 3 to JavaScript and supports browser, Node.js, and serverless.

You have two options:

1. FP-native Scala frontends (recommended if you want to “go FP”)

  • Laminar – FRP-style Scala.js UI library, very clean reactive model, great for SPAs.
  • Tyrian – Elm-inspired Scala.js framework aimed at SPAs, built with Cats Effect/FS2 under the hood.

Tyrian in particular is very close to Elm’s architecture: a Model, a Msg ADT, and an update function. You get Elm-style reasoning while staying in Scala and reusing your Cats Effect knowledge.

If you’re willing to move away from React on the front-end, Laminar/Tyrian are a clean, fully FP story.

2. Keep React, but write it in Scala

If you want to stick with React specifically, you can use Scala.js bindings like Slinky or scalajs-react (they’re listed in the Scala.js library index next to Laminar/Tyrian).

You still get:

  • Strong typing
  • FP style (especially if you keep using Cats Effect / ZIO for your effectful bits)
  • JS interop when needed

But you keep the React mental model (components, hooks, etc.). It’s not as “pure FP” as Laminar/Tyrian, but it’ll feel familiar as a TS/React dev.

CLIs

For CLIs, Scala is fine:

  • decline – composable, Cats-based CLI parser, inspired by Haskell’s optparse-applicative.
  • case-app – case-class-based, type-level CLI parser, widely used (Scala CLI, coursier).

Pair either with Cats Effect / ZIO, and optionally Scala Native if you want self-contained native binaries.

This covers your “occasional CLIs” requirement without introducing another language.

“Can I do what I do with React/Express, but in Scala?”

Realistic mapping:

  • Express-style APIhttp4s or ZIO HTTP (or Cask if you want something more minimal). You run on the JVM instead of Node, but conceptually it’s an HTTP server with middleware, routing, and handlers.
  • React front-end
    • Either Scala.js + React bindings (keep React), or
    • Scala.js + Tyrian/Laminar (Elm-style FP front-end).

The big difference from PureScript is: with Scala.js you’re not stuck in a tiny ecosystem. You can:

  • Interop with JavaScript directly whenever needed.
  • Use Scala.js-native UI libs like Laminar/Tyrian.
  • Share domain types and codecs between backend and frontend via a cross-compiled common module (JVM + JS).

So you’re not just writing FP domain code with a mountain of JS glue; you can keep almost everything in Scala if you want.

Feature highlights that pay off when you go functional

These matter in day-to-day web/API work:

  • HKTs – the reason Cats/ZIO/Kyo can exist in the first place, and why you can write generic abstractions over F[_].
  • Typeclass derivation – auto-derive JSON codecs, configs, schema descriptions, etc. Very handy for web APIs.
  • Union & intersection types, opaque types, newtypes (yantl, etc.) – build rich domain models without runtime overhead, and keep the compiler screaming when you mess up.
  • Implicits / givens – the mechanism behind typeclasses and a lot of FP “magic.”

You get most of Haskell’s type-level power, but with pragmatic escape hatches and a much larger “boring Java” ecosystem if you just need a library that works.

Learning path (specifically tailored to you)

If I were you, with your background, I’d do this:

  1. Write a small CLI tool in Scala 3 + Cats Effect + decline or case-app. Get comfortable with the syntax, IO, error handling, and basic effect composition.
  2. Build a small HTTP API with http4s or ZIO HTTP, using Doobie + doobie-typesafe + yantl for DB and domain modelling. This will show you how FP applies to your usual API + DB stack.
  3. Pick a front-end story:
    • If you want Elm-like FP front-end: Tyrian or Laminar.
    • If you want to keep React exactly: Scala.js + React bindings.
  4. Go full-stack with a shared common module:
    • Shared domain types
    • Shared JSON codecs
    • Shared endpoint definitions via Tapir.
  5. If you want guided, end-to-end practice: Rock the JVM – “Typelevel Rite of Passage” course builds exactly this: a full-stack Scala 3 jobs platform with Cats, Cats Effect, Doobie, http4s, and Tyrian, from scratch.

That course is basically a concrete answer to your question: “is there a language with ecosystems for web UIs, web APIs, CLIs, DB, in a functional style?” – yes: Scala, and that stack.

Bottom line

If your goal is:

  • Learn FP properly, not just dabble.
  • Still build real-world backends, frontends, and CLIs with good libraries.
  • Avoid getting stuck in a research ecosystem.

Then Scala 3 with the Typelevel / ZIO / Kyo stacks plus Scala.js is a very good fit.

Use Haskell/Elm/PureScript for inspiration and reading; write production code in Scala.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment