Scala Native
Cats Effect supports Scala Native since 3.3.14
.
Scala Native example
Here's an example of a Hello world project compiled to a native executable using sbt-scala-native plugin.
// project/plugins.sbt
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.4.7")
// build.sbt
ThisBuild / organization := "com.example"
ThisBuild / scalaVersion := "2.13.8"
lazy val root = project.in(file("."))
.enablePlugins(ScalaNativePlugin)
.settings(
name := "cats-effect-3-hello-world",
libraryDependencies += "org.typelevel" %%% "cats-effect" % "3.5.7",
Compile / mainClass := Some("com.example.Main")
)
// src/main/scala/com/example/Main.scala
package com.example
import cats.effect.{IO, IOApp}
object Main extends IOApp.Simple {
def run: IO[Unit] = IO.println("Hello Cats Effect!")
}
The code can be compiled using sbt nativeLink
and a native executable can then
be found under target/scala-2.13/cats-effect-3-hello-world-out
, and executed as any native
executable with the benefit of a really fast startup time (hyperfine
is a command line benchmarking tool written in Rust)
$ ./target/scala-2.13/cats-effect-3-hello-world-out
Hello Cats Effect!
$ hyperfine ./target/scala-2.13/cats-effect-3-hello-world-out
Benchmark 1: ./target/native-image/cats-effect-3-hello-world-out
Time (mean ± σ): 7.5 ms ± 1.2 ms [User: 3.6 ms, System: 2.3 ms]
Range (min … max): 6.0 ms … 17.9 ms 141 runs
Another way to get your cats effect app compiled to a native executable is to leverage the package command of scala-cli, like in the example
Limitations
The Scala Native runtime is single-threaded, similarly to ScalaJS. That's why the IO#unsafeRunSync
is not available.
Be careful with IO.blocking(...)
as it blocks the thread since there is no dedicated blocking thread pool.
For more in-depth details, see the article with explanations of how the Native runtime works.
Showcase projects
- scala-native-ember-example shows how you can run the http4s server as a native binary