Skip to content

Scala

Bufrnix supports generating Scala code from Protocol Buffer definitions using ScalaPB, a protocol buffer compiler plugin for Scala.

To enable Scala code generation, add the following to your flake.nix:

protoGen = bufrnix.lib.mkBufrnixPackage {
inherit pkgs;
config = {
root = ./proto;
languages = {
scala = {
enable = true;
};
};
};
};
OptionTypeDefaultDescription
enablebooleanfalseEnable Scala code generation
packagepackagepkgs.scalapbThe ScalaPB package to use
outputPathstring"gen/scala"Output directory for generated Scala code
optionslist of strings[]Options to pass to ScalaPB
scalaVersionstring"3.3.3"Scala version for generated build file
scalapbVersionstring"1.0.0-alpha.1"ScalaPB version
sbtVersionstring"1.10.5"SBT version for generated build file
sbtProtocVersionstring"1.0.7"sbt-protoc plugin version
projectNamestring"generated-protos"Project name for generated build file
projectVersionstring"0.1.0"Project version for generated build file
organizationstring"com.example"Organization for generated build file
generateBuildFilebooleanfalseGenerate build.sbt file
generatePackageObjectbooleanfalseGenerate package objects for proto packages

To enable gRPC code generation:

scala = {
enable = true;
grpc = {
enable = true;
options = []; # Additional options for gRPC generation
};
};

To enable JSON serialization support:

scala = {
enable = true;
json = {
enable = true;
json4sVersion = "0.7.0"; # scalapb-json4s version
};
};

To enable validation support:

scala = {
enable = true;
validate = {
enable = true;
};
};

You can pass options to ScalaPB using the options field:

scala = {
enable = true;
options = [
"flat_package" # Don't append file name to package
"java_conversions" # Generate Java conversions
"single_line_to_proto_string" # Single line toString
];
};

Common ScalaPB options:

  • flat_package - Don’t append file name to package
  • java_conversions - Generate converters to/from Java protos
  • grpc - Generate gRPC service stubs (also available via grpc.enable)
  • single_line_to_proto_string - Generate single line toString methods
  • no_lenses - Don’t generate lenses
  • retain_source_code_info - Retain source code info in descriptors

When generateBuildFile is enabled, bufrnix generates a complete SBT project structure:

scala = {
enable = true;
generateBuildFile = true;
projectName = "MyProtoProject";
organization = "com.mycompany";
scalaVersion = "3.3.3";
};

This generates:

  • build.sbt - Main build file with ScalaPB dependencies
  • project/plugins.sbt - SBT plugins including sbt-protoc
  • project/build.properties - SBT version configuration
proto/person.proto
syntax = "proto3";
package example.v1;
option java_package = "com.example.v1";
message Person {
int32 id = 1;
string name = 2;
string email = 3;
}
import com.example.v1.person._
// Create a person
val person = Person(
id = 1,
name = "John Doe",
email = "john@example.com"
)
// Serialize to bytes
val bytes = person.toByteArray
// Parse from bytes
val parsed = Person.parseFrom(bytes)
// Convert to JSON (if json support is enabled)
import scalapb.json4s.JsonFormat
val json = JsonFormat.toJsonString(person)
proto/greeter.proto
syntax = "proto3";
package example.v1;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
import example.v1.greeter._
import io.grpc.stub.StreamObserver
// Implement the service
class GreeterImpl extends GreeterGrpc.Greeter {
override def sayHello(
request: HelloRequest,
responseObserver: StreamObserver[HelloReply]
): Unit = {
val reply = HelloReply(
message = s"Hello ${request.name}!"
)
responseObserver.onNext(reply)
responseObserver.onCompleted()
}
}

Include necessary tools in your development shell:

devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
jdk17 # or jdk21
sbt # Scala build tool
scala_3 # or scala_2_13
protobuf # protoc compiler
];
};
  1. Package Names: Use option java_package in your proto files to control the generated package structure
  2. Case Classes: ScalaPB generates immutable case classes by default
  3. Collections: Repeated fields become Seq[T] in Scala
  4. Optionals: Proto3 optional fields become Option[T] in Scala
  5. Enums: Proto enums become sealed traits with companion objects
  6. Unknown Fields: ScalaPB preserves unknown fields by default for forward compatibility
  1. Missing Dependencies: Ensure your build.sbt includes the ScalaPB runtime:

    libraryDependencies += "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf"
  2. Import Errors: Make sure the generated code directory is added to your source paths:

    Compile / sourceDirectories += file("gen/scala")
  3. Version Conflicts: Ensure your Scala version matches between ScalaPB and your project

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    bufrnix = {
      url = "github:conneroisu/bufrnix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = {
    nixpkgs,
    flake-utils,
    bufrnix,
    ...
  }:
    flake-utils.lib.eachDefaultSystem (
      system: let
        pkgs = nixpkgs.legacyPackages.${system};

        # Generate protobuf code
        protoGen = bufrnix.lib.mkBufrnixPackage {
          inherit pkgs;

          config = {
            root = ./proto;
            languages = {
              scala = {
                enable = true;
                generateBuildFile = true;
                projectName = "ScalaProtoExample";
                organization = "com.example.protobuf";
              };
            };
          };
        };
      in {
        packages = {
          default = protoGen;
          proto = protoGen;
        };

        devShells.default = pkgs.mkShell {
          buildInputs = with pkgs; [
            jdk17
            sbt
            scala_3
            protobuf
          ];

          shellHook = ''
            echo "Scala Proto Example Development Shell"
            echo "Run 'nix run' to generate proto code"
            echo ""
            echo "For development:"
            echo "  1. Generate protos: nix run"
            echo "  2. Compile: sbt compile"
            echo "  3. Run: sbt run"
          '';
        };

        apps = {
          default = {
            type = "app";
            program = "${protoGen}/bin/bufrnix";
          };
        };
      }
    );
}