License: MIT

A Scala micro-library for generating type-safe builder for any case class via annotation.


Add resolver to bintray repo:

resolvers += "pcejrowski maven" at ""

and add the following dependency to your build.sbt.

libraryDependencies += "com.github.pcejrowski" %% "safe-builder" % "0.1.4"

or, if you are using Scala JS or Scala Native:

libraryDependencies += "com.github.pcejrowski" %%% "safe-builder" % "0.1.4"

Finally, enable Macro Paradise:

addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)


Annotate your class with @builder

import safebuilder.annotation.builder

case class Foo(name: Option[String],
               bar: Boolean,
               baz: Either[Float, String],
               seq: Seq[Int])

and enjoy builder API with compile-time correctness verification.

val foo = Foo()
  .withSeq(1, 2, 3)

The library will make sure that all non-optional fields are filled when you invoke build. Moreover, no field value can be overwritten. That means, for already defined class Foo following cases will not compile:


because required parameters (baz and bar, respectively) are not defined.

Following functions are generated depending on the type of the field:

Field name Type Functions
foo A withFoo(foo: A)
foo Option[A] withFoo(foo: A)
foo Either[A,B] withFoo(foo: A)
withFoo(foo: B)
foo Boolean fooEnabled
foos Seq[A] withFoos(foos: Seq[A])
withFoos(foo: A, foos: A*)
appendFoos(foo: A)
prependFoos(foo: A)


If there is a default (rhs) value defined for a field (e.g. case class Foo(foo: String = "foo"), the invocation of mutator for that field is no longer required and the default value will be used. Since the default value for Option is None by default, this setup will also accept to use Some[_] as a default value, even though it's considered to be an ambiguous anti-pattern.


Add -Ymacro-debug-lite flag to scalac options and generated source code will show up in the console when you compile.

scalacOptions in Compile += "-Ymacro-debug-lite"


Running tests

Tests are configured to run on all platforms (JVM, JS, Native). Simply invoke sbt "+test"

Releasing artifacts

safe-builder uses Simply invoke release from the root project to release all artifacts.