close icon
daily.dev platform

Discover more from daily.dev

Personalized news feed, dev communities and search, much better than whatโ€™s out there. Maybe ;)

Start reading - Free forever
Start reading - Free forever
Continue reading >

Scalafix Tutorial: Setup, Rules, Configuration

Scalafix Tutorial: Setup, Rules, Configuration
Author
Nimrod Kramer
Related tags on daily.dev
toc
Table of contents
arrow-down

๐ŸŽฏ

Learn how to set up Scalafix for Scala code refactoring and linting. Discover rules, configurations, and best practices to enhance your codebase.

Scalafix is a code refactoring and linting tool that automatically fixes and improves Scala code. Here's what you need to know:

What Scalafix Does:

  • Spots and fixes code issues automatically
  • Updates old code patterns to modern syntax
  • Enforces consistent code style
  • Helps with Scala version migrations

Key Components:

Component What It Does When to Use
Syntactic Rules Checks code structure Simple pattern matching
Semantic Rules Analyzes code meaning Complex refactoring
Built-in Rules Ready-to-use fixes Common code patterns
Custom Rules Your own rules Team-specific needs

Quick Setup:

  1. Add to project/plugins.sbt:
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.13.0")
  1. Update build.sbt:
inThisBuild(List(
  semanticdbEnabled := true,
  semanticdbVersion := scalafixSemanticdb.revision
))

Requirements:

Tool Supported Versions
Java 8, 11, 17, 21 LTS
Scala 2.12.20, 2.13.15, 3.3.4, 3.5.1
sbt Latest version

Most Used Rules:

  • RemoveUnused: Cleans up dead code
  • ExplicitResultTypes: Adds missing types
  • OrganizeImports: Structures imports
  • DisableSyntax: Blocks unwanted patterns

This guide walks you through setting up Scalafix, using built-in rules, creating custom rules, and integrating with your build tools.

Before You Start

Here's what you need to set up Scalafix on your machine.

Required Tools

Tool Version Notes
Java 8, 11, 17, or 21 LTS Min. Java 11 for Metals server
Scala 2.12.20, 2.13.15, 3.3.4 LTS, or 3.5.1 No support for Scala 2.11
sbt Latest Build tool for Scala
IDE VS Code or IntelliJ With Metals extension

Setting Up Scala

Scala

Start by installing Java. Then add these settings to your .jvmopts file:

-Xss8m
-Xms1G
-Xmx8G

Build Tool Setup

First, add this to project/plugins.sbt:

addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.13.0")

Next, update your build.sbt:

inThisBuild(
  List(
    scalaVersion := "2.13.15",
    semanticdbEnabled := true,
    semanticdbVersion := scalafixSemanticdb.revision
  )
)

IDE Setup

For VS Code:

  1. Install Metals extension
  2. Remove other Scala extensions
  3. Run this command:
scala-cli setup-ide . --scala 2.13

This creates two files:

  • .bsp/scala-cli.json for Build Server Protocol
  • .scala-build/ide-options-v2.json for IDE settings

For IntelliJ:

  1. Install Scala plugin
  2. Import project as sbt project
  3. Enable Build Server Protocol

Don't forget to restart your IDE after making these changes.

Setting Up Scalafix

Scalafix

Here's how to add Scalafix to your project.

Adding the Plugin

In project/plugins.sbt, add:

addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.13.0")

For Scala 2.11, use this instead:

addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.10.4")

Setting Up SemanticDB

SemanticDB

Add to your build.sbt:

inThisBuild(
  List(
    scalaVersion := "2.13.15",
    semanticdbEnabled := true,
    semanticdbVersion := scalafixSemanticdb.revision,
    scalacOptions += "-Wunused:imports"
  )
)

For Scala 2.12, use this option instead:

scalacOptions += "-Ywarn-unused-import"

Project Setup

You'll need these folders:

Directory What It's For
rules/ Where you put rule code
input/ Code to check
output/ What code should look like after rules run
tests/ Test setup files

Want a quick start? Run:

sbt new scalacenter/scalafix.g8 --repo="YourRepoName"

Basic Config File

Make a .scalafix.conf file:

rules = [
  DisableSyntax
]

DisableSyntax.noFinalize = true

For CI, add:

lint.error = [
  ".*"
]

To run Scalafix:

sbt "scalafix RemoveUnused"   # one project
sbt scalafixAll              # all projects

For tests:

sbt "Test / scalafix"

Scalafix Rules Explained

Scalafix comes with two types of rules to fix and improve your code.

Built-in Rules

Here's what each built-in rule does:

Rule Name What It Does When to Use
ExplicitResultTypes Adds type annotations for public members For clearer code interfaces
OrganizeImports Cleans up and structures imports To maintain consistent import style
ExplicitNonNullaryApply Adds () to Java methods overridden in Scala For Java interop
IllegalImports Blocks usage of specific imports To prevent unwanted dependencies
ConstructorProcedureSyntax Removes old constructor syntax For modern Scala code
FinalObject Removes unneeded final modifiers Code cleanup

Rule Types

Scalafix splits rules into two main groups:

Type Description Requirements
Syntactic Looks at code structure Works out of the box
Semantic Checks code meaning and types Needs SemanticDB compiler plugin

Using Rules

Pick rules based on what you want to fix:

  • Need Java/Scala interop? Go with ExplicitNonNullaryApply
  • Want better type safety? Add ExplicitResultTypes
  • Looking for clean imports? Use OrganizeImports

Setting Up Rules

Here's how to set up rules in .scalafix.conf:

rules = [
  DisableSyntax,
  ExplicitResultTypes
]

# Rule-specific settings
ExplicitResultTypes {
  memberVisibility = [
    public,
    protected
  ]
  skipSimpleDefinitions = false
}

# Import blocks
OrganizeImports {
  groups = [
    "java.",
    "scala.",
    "*"
  ]
}

Scalafix runs rules in parallel, making it faster than regular compiler plugins.

Basic Settings

Here's how to set up and use Scalafix configuration:

Config File Layout

Scalafix looks for .scalafix.conf in your project's root folder. It uses HOCON format:

# Pick your rules
rules = [
  DisableSyntax,
  ExplicitResultTypes
]

# Set rule options
DisableSyntax.noFinalize = true
ExplicitResultTypes.skipSimpleDefinitions = false

HOCON Basics

What How Example
Key-Value : or = rule = value
Comments # or // # Comment here
Objects {} rule { key = value }
Arrays [] rules = [item1, item2]

Rule Settings

You can configure rules in three ways:

Type What It Does Example
Global Sets rules for everything rules = [DisableSyntax]
Per-Rule Sets one rule's options DisableSyntax.noFinalize = true
Triggered Runs rules automatically triggered.rules = [RemoveUnused]

Common Settings

Here's what most teams use:

# Pick rules
rules = [
  DisableSyntax,
  RemoveUnused
]

# Auto-run these
triggered.rules = [
  DisableSyntax
]

# Handle errors
lint.error = [
  "DisableSyntax"
]

# Handle imports
OrganizeImports {
  groups = [
    "java.",
    "scala.",
    "*"
  ]
}

Want to change settings from the command line? Use --settings:

scalafix --settings.DisableSyntax.noFinalize=true

Using Built-in Rules

Scalafix ships with 4 key rules to keep your Scala code clean. Let's see how each one works:

Type Annotations

The ExplicitResultTypes rule adds missing type info to your methods:

// Before
def process = List(1,2,3).map(_ * 2)

// After
def process: List[Int] = List(1,2,3).map(_ * 2)

Here's how to set it up in .scalafix.conf:

ExplicitResultTypes {
  skipSimpleDefinitions = false
  skipLocalImplicits = true
}

Import Cleanup

The OrganizeImports rule keeps your imports tidy. Add this to your config:

OrganizeImports {
  groups = [
    "java.",
    "scala.",
    "*"
  ]
  removeUnused = true
  blankLines = 1
}
Setting What It Does Default
groups Sets import order ["*"]
removeUnused Drops unused imports true
blankLines Spaces between groups 1

Removing Unused Code

The RemoveUnused rule cuts dead code. First, turn on these compiler flags:

  • Scala 2.12: -Ywarn-unused
  • Scala 2.13: -Wunused
  • Scala 3.3.4+: -Wunused:all

Then configure what to remove:

RemoveUnused {
  imports = true
  privates = true
  locals = true
  patternvars = true
  params = true
}
Option Removes
imports Dead imports
privates Unused private items
locals Unused local defs
patternvars Dead pattern vars
params Unused params (Scala 2)

Syntax Restrictions

The DisableSyntax rule blocks code patterns you don't want:

DisableSyntax {
  noVars = true
  noNulls = true
  noReturns = true
  noWhileLoops = true
  noFinalize = true
}
Rule Stops Usage Of
noVars var
noNulls null
noReturns return
noWhileLoops while
noFinalize finalize

Making Custom Rules

Let's walk through how to build custom rules for your code checks and fixes.

Creating Rules

Your project needs a specific folder setup. For a single project:

repository/
โ”œโ”€โ”€ build.sbt
โ””โ”€โ”€ src/
    โ””โ”€โ”€ scalafix/
        โ”œโ”€โ”€ resources/META-INF/services/
        โ”‚   โ””โ”€โ”€ scalafix.v1.Rule
        โ””โ”€โ”€ scala/fix/
            โ””โ”€โ”€ MyRule1.scala

Working with multiple projects? Use this structure:

repository/
โ”œโ”€โ”€ build.sbt
โ””โ”€โ”€ scalafix/
    โ”œโ”€โ”€ input/src/main/scala/fix/
    โ”œโ”€โ”€ output/src/main/scala/fix/
    โ”œโ”€โ”€ rules/src/main/scala/fix/
    โ””โ”€โ”€ tests/src/test/scala/fix/

Testing Rules

The scalafix-testkit helps you test your rules. Here's what each folder does:

Folder Purpose
input Code you want to test
output How code should look after
rules Your rule code
tests Test setup files

Here's a test case example:

// Input file
val x = List(1, "") // assert: NoInfer.any

// Output file
val x: List[Any] = List(1, "")

Rule Writing Tips

You can write two types of rules:

Type Function When to Use
Semantic Changes code Method renames, pattern fixes
Syntactic Spots problems Blocks bad syntax

Look at this semantic rule that adds names to arguments:

// Before
complete(true)

// After
complete(isSuccess = true)

Finding and Fixing Bugs

Here's how to debug your rules:

1. Run your rule:

sbt> scalafix MyRule1

2. Look at what changed between input and output

3. Add tests for weird cases

4. Use // scalafix:ok to skip specific lines

For CI, add this to your build:

scalafixDependencies += "org.fix" %% "custom-rule" % "1.0.0"

Run your checks:

sbt "scalafixEnable; scalafixAll --check"
sbb-itb-bfaad5b

Build Tool Setup

Here's how to set up Scalafix in your project:

sbt Setup

First, add the Scalafix plugin to project/plugins.sbt:

addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.13.0")

For Scala 2.x, put these settings in build.sbt:

inThisBuild(
  List(
    scalaVersion := "2.12.20",
    semanticdbEnabled := true,
    semanticdbVersion := scalafixSemanticdb.revision
  )
)

Multiple Projects

Working with multiple modules? Here's how to structure your build.sbt:

lazy val core = (project in file("core"))
  .settings(commonSettings)

lazy val mod1 = (project in file("mod1"))
  .dependsOn(core)
  .settings(commonSettings)
Setting What It Does Example
commonSettings Shares config across modules semanticdbEnabled := true
ThisBuild Sets project-wide config scalaVersion := "2.12.20"
dependsOn Links modules together mod1.dependsOn(core)

CI Pipeline Setup

Add these commands to your CI pipeline:

# Verify code without changes
sbt "scalafixEnable; scalafixAll --check"

# Speed up builds with caching
cache:
  paths:
    - ~/.cache/coursier
Command When to Use What It Does
--check In CI Fails if fixes needed
scalafixAll All modules Fixes every project
scalafixEnable Initial setup Activates Scalafix

Auto-checks

Want Scalafix to run automatically? Add this to build.sbt:

scalafixOnCompile := true

Configure auto-run rules in .scalafix.conf:

triggered.rules = [
  DisableSyntax
]
Setting What Happens
scalafixOnCompile Checks during compilation
triggered.rules Rules that run automatically
lint.error Treats warnings as errors

Advanced Settings

Multi-project Config

Here's how to share configs across Scala projects using a core module:

# core/application.conf
rules = [
  DisableSyntax
  NoAutoTupling
]

Want to add these core settings to other modules? Just include them:

# mod1/application.conf
include "core/application.conf"

# Add module-specific rules
rules += RemoveUnused
Module Type Config Location Purpose
Core core/src/main/resources Base rules, shared settings
Sub-modules modX/src/main/resources Module-specific rules
Test modules modX/src/test/resources Test-specific configs

Custom Rule Settings

Here's how to set up rules in .scalafix.conf:

# Customize rule settings
DisableSyntax.noVars = true
DisableSyntax.noNulls = true
RemoveUnused.imports = true

# Override lint behavior
lint.error = [
  ".*"
  "-UnusedScalafixSuppression"
]
Setting Type Example Effect
Rule-specific noVars = true Controls individual rule options
Lint levels lint.error Sets warning severity
Triggers triggered.rules Rules that run on compile

Error Management

Got Scalafix issues? Here's what to do:

Error Type Solution Setting
Memory errors Increase JVM heap -Xmx8G
Rule timeouts Skip slow rules triggered.rules -= ExplicitNonNullaryApply
Build failures Treat as warnings SCALA_SCALAFIX_DISABLE_ERRORS = true

Speed Improvements

Want faster Scalafix runs? Try these settings:

Setting Value Impact
JVM options -XX:+UseParallelGC Better throughput
JIT settings -XX:MaxInlineLevel=20 10-20% faster compilation
Memory -Xms512M -Xmx4G Prevents OOM errors
GraalVM Latest version Up to 50% faster processing

Pro tip: For codebases with over 10,000 lines, skip the ExplicitNonNullaryApply rule. It can eat up memory because of SemanticDB limits.

Fix Common Problems

Here's what you need to know about fixing Scalafix issues:

Known Issues

Issue Error Message Fix
Missing dependencies Error downloading org.scalameta:semanticdb-scalac_2.13.8:4.4.28 Update sbt-scalafix plugin to v0.9.28
SemanticDB not found SemanticDB not found: src/main/scala/my/package/Something.scala Add -Yrangepos to scalacOptions
Object loading error error while loading Object, Missing dependency 'object scala.native' Check Scala version compatibility
Memory issues java.lang.OutOfMemoryError Add JVM flags: -Xms512M -Xmx4G

Error Guide

Error Type Meaning Action
Scala version mismatch Wrong semanticdb-scalac version Add semanticdbVersion := scalafixSemanticdb.revision
Plugin errors Missing compiler plugin Add addCompilerPlugin("org.scalameta" % "semanticdb-scalac")
Build failures Failed dependency resolution Update build.sbt with correct versions
Rule timeouts Rule processing takes too long Skip slow rules in config

Fix Configuration

Here's what you need in your build.sbt:

addCompilerPlugin("org.scalameta" % "semanticdb-scalac" % "4.10.2" cross CrossVersion.full)
scalacOptions += "-Yrangepos"
semanticdbVersion := "4.4.11"

Handle Rule Conflicts

Conflict Type Example Solution
Version conflicts Different Scala versions Use cross CrossVersion.full
Rule ordering Import rules clash Set explicit order in config
Multiple projects Different settings per module Use separate .scalafix.conf files
Plugin conflicts Compiler plugin clashes Check plugin compatibility

Pro tip: Most version-related errors happen when you update Scala but forget to update the Scalafix plugin. Always check your semanticdb version in build.sbt after updates.

Tips and Tricks

File Organization

Here's how to set up your Scalafix files:

Location Purpose Example
.scalafix.conf Main config file rules = [RemoveUnused]
.scalafix/ Custom rules directory rules/CustomLint.scala
project/plugins.sbt Plugin definitions addSbtPlugin("ch.epfl.scala" % "sbt-scalafix")
.github/workflows/ CI integration scalafix.yml for auto-fixes

Rule Selection

Here's what matters when picking rules:

Factor What to Check Action
Build time CI logs Skip slow rules in large projects
Memory usage JVM metrics Use -Xmx4g for big codebases
Project size LOC count Split configs for different modules
Team size Developer count Add more strict rules for larger teams

Config Management

Here's a simple config setup:

// .scalafix.conf
rules = [
  RemoveUnused,
  ExplicitResultTypes,
  LeakingImplicitClassVal
]

ExplicitResultTypes {
  memberKind = [Val, Def, Var]
  skipSimpleDefinitions = false
}

Git Integration

Set up GitHub Actions for Scalafix:

name: "Scalafix"
on: [pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Run Scalafix
        env:
          JAVA_OPTS: -Xmx8G -Xms1G -Xss8M
        run: sbt "scalafix RemoveUnused"
Integration Point Command Purpose
Pre-commit sbt scalafix Check code before commits
PR checks sbt "scalafix --check" Verify PR changes
Auto-fixes sbt "scalafix RemoveUnused" Fix issues automatically
Batch fixes git diff --name-only HEAD~1 | xargs scalafix Fix changed files only

Want faster builds? Keep your build graph shallow.

Boost your build speed with these JVM settings:

Setting Value Impact
-XX:MaxInlineLevel 20 10-20% faster compilation
-XX:+UseParallelGC - Better for Java 9/11
-Xmx 2g-4g Handles large projects

GraalVM performance options:

Component Speedup Use Case
Native Image 10-50% CI builds
JIT Compiler 20-30% Local development
Enterprise Edition 30-40% Production builds

Help and Resources

Here's what you need to know about getting started with Scalafix and finding help when you need it.

Core Documentation

The docs cover everything you need to run Scalafix:

Setup Details
Java Support Java 8/11/17/21 LTS
Scala Versions 2.12.20, 2.13.15, 3.3.4, 3.5.1
OS Support macOS, Linux, Windows
Build Tools sbt, Maven, Mill, Gradle
Rule Categories Hygiene, Migration, Code Generation

These community-made rules can help improve your code:

Rule What It Does Find It Here
unified Makes code consistent ghostbuster91/scalafix-unified
named-params Adds parameter names jatcwang/scalafix-named-params
scaluzzi Checks Scalazzi rules vovapolu/scaluzzi
pixiv-rule Catches bad patterns pixiv/scalafix-pixiv-rule

Want to use these rules? Add them to your build:

// build.sbt
ThisBuild / scalafixDependencies += "GROUP" %% "ARTIFACT" % "VERSION"

Where to Get Help

Need help? Here's where to go:

Channel When to Use It How to Use It
GitHub Issues Report bugs, ask for features Post on Scalafix repo
Issue Triage Help other users Get daily emails
Pull Requests Fix issues yourself Fork and submit changes
Community Rules Share your own rules Send a pull request

Stay Up to Date

Keep track of what's new:

Where to Look What You'll Find How It's Shown
GitHub Releases Version info Release notes
Scaladex New rule listings Package info
Build Files Rule changes Dependency updates
Config Files Setting updates HOCON format

Check if your rules need updates:

sbt "scalafix --check"

Update rules on the fly:

sbt "scalafix dependency:RULE@GROUP::ARTIFACT:VERSION"

Summary

Here's what you need to know about Scalafix:

Component Key Details Usage
Setup Requirements Java 8/11/17/21 LTS, Scala 2.12+ Basic project configuration
Rule Types Syntactic, Semantic Code analysis and transformation
Built-in Rules ExplicitResultTypes, NoAutoTupling, OrganizeImports Ready-to-use code improvements
SemanticDB Compiler plugin Powers semantic analysis

Let's look at some before/after examples:

Task Before After
Fix Procedure Syntax def main(args: Seq[String]) { def main(args: Seq[String]): Unit = {
Add Volatile lazy val x = value @volatile lazy val x = value
Clean Imports Messy imports Organized by groups

What can Scalafix do? It helps you:

  • Fix code automatically
  • Update old code to modern syntax
  • Find and change specific patterns
  • Work with sbt, Maven, Mill, and Gradle
  • Build your own rules

Here's where teams use it most:

Case Description Tool Support
Code Cleanup Remove unused imports RemoveUnused rule
Type Safety Add missing type annotations ExplicitResultTypes rule
Standards Enforce coding standards DisableSyntax rule
Migration Update deprecated features ProcedureSyntax rule

Bottom line: Scalafix makes your code better by fixing issues, keeping things consistent, and helping you move to newer Scala versions. It's like having an extra team member who's really good at spotting and fixing code problems.

FAQs

What is the use of Scalafix?

Scalafix is a tool that helps you fix and improve Scala code automatically. It's like a smart assistant that spots issues and helps clean up your code.

Here's what Scalafix does:

Feature Description Example Use Case
Code Analysis Reads your code structure Spots old code patterns
Linting Flags code problems Finds imports you don't need
Refactoring Changes code automatically Adds missing types
Custom Rules Lets you make your own rules Matches your team's style

Want to start using Scalafix? Here's how:

  1. Get it running: Add it to your build and set up tests
  2. Find patterns: Tell it what code to look for
  3. Check methods: Look up how functions work
  4. Spot problems: Set up warnings for bad code
  5. Make it flexible: Add settings to your rules
  6. Share it: Use it locally or share with others

Here's how to fit Scalafix into your coding:

Where to Use It What It Does Why It Helps
sbt Plugin Works with your build tool Helps you write rules
IDE Works in your editor Shows issues right away
CI Pipeline Checks code automatically Keeps code clean
Maven Central Shares rules with others Everyone uses same rules

Want to make your own rules? Use the scalafix.g8 template. It gives you:

  • rules/: Where you write rules
  • input/: Code to test on
  • output/: What code should look like
  • tests/: Check if rules work

To test your rules, just run tests / test.

Related posts

Why not level up your reading with

Stay up-to-date with the latest developer news every time you open a new tab.

Read more