sbt 配置的核心就三件事:锁定 sbt 版本、管好依赖仓库、把模块边界写进构建文件。 把 project/build.properties、build.sbt 和全局 repositories 这三处理顺,下载慢、依赖冲突、多模块不识别的问题基本都能定位到具体位置。

sbt 配置文件 build.sbt 怎么写:从空项目到可运行
先落盘三个文件
你打开一个 Scala 项目,先别急着加插件,先看这三个文件在不在:
project/build.properties:固定 sbt 版本,sbt.version=1.10.7,版本号以官方发布页为准,团队统一比追新更重要。build.sbt:写项目名、Scala 版本、依赖、编译参数。project/plugins.sbt:放打包、代码检查、发布类插件。
路径结构大致如下:
demo/ ├── build.sbt ├── project/ │ ├── build.properties │ └── plugins.sbt └── src/main/scala
project/build.properties 里只写一行:
sbt.version=1.10.7
这行看似简单,作用很直接,CI 和本地机器启动时会按这个版本拉取 sbt,减少“我这边能跑、你那边报错”的情况。
最小可用骨架
一个能编译、能测试的 build.sbt 可以这样写:
ThisBuild / scalaVersion := "2.13.14"
ThisBuild / organization := "com.example"
lazy val root = (project in file("."))
.settings(
name := "demo",
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % "2.12.0",
"org.scalatest" %% "scalatest" % "3.2.19" % Test
)
)
这里有两个符号要分清:
- 会自动拼接 Scala 二进制版本,Scala 库常用。
- 不拼 Scala 版本,Java 库或明确带版本后缀的依赖常用。
% Test表示只在测试作用域可见,不会打进主运行包。
执行顺序建议固定为:
sbt compile看主代码能不能编译。sbt test看测试依赖和作用域对不对。sbt run看入口类是否识别。
依赖冲突先跑哪条命令
依赖冲突不要靠猜,进入 sbt 交互界面后按顺序执行:
sbt dependencyTree:看完整依赖树。sbt evicted:看被升级或淘汰的版本。sbt update:重新解析依赖,确认仓库是否可用。
作用域写错会怎样
% Test 写成默认作用域,测试库会被打进运行包;% Provided 写成默认作用域,容器环境可能重复加载,声明方式和场景可以对照:
| 写法 | 含义 | 常见场景 |
|---|---|---|
| 普通依赖 | Java 库 | |
| 拼接 Scala 版本 | Scala 生态库 | |
% Test |
测试作用域 | ScalaTest、Mock 库 |
% Provided |
运行环境提供 | Servlet、Spark 相关依赖 |
配置里最容易踩的三个坑
- sbt 版本和插件版本不匹配:插件文档通常会写支持的 sbt 大版本,先看再升。
- JDK 版本不一致:本地是 JDK 17,CI 还是 JDK 8,编译参数和字节码目标容易出偏差。
- 把密钥写进 build.sbt:发布仓库的用户名密码应放在
~/.sbt/credentials.sbt或 CI 密钥变量里,不要提交到 Git。
Windows 下 sbt 配置国内镜像的完整路径
先处理 JAVA_HOME 和路径
Windows 上先确认 JDK 能被 sbt 找到,在 PowerShell 里可以这样临时设置:
$env:JAVA_HOME="C:Program FilesJavajdk-17" $env:Path="$env:JAVA_HOMEbin;$env:Path" sbt -v
-v 会打印启动参数和 JVM 信息,项目路径尽量不要带中文和空格;如果必须带,优先升级到较新的 sbt 启动脚本,减少路径解析问题。

全局 repositories 文件放哪
全局仓库文件放在:
C:Users你的用户名.sbtrepositories
一个常见的国内镜像写法是:
[repositories] local maven-central aliyun: https://maven.aliyun.com/repository/public aliyun-sbt-plugin: https://maven.aliyun.com/repository/sbt-plugin, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]
写完还要让 sbt 覆盖项目里声明的仓库,否则部分依赖仍会走默认地址,可以在 %USERPROFILE%.sbtopts 里加一行:
-Dsbt.override.build.repos=true
然后执行:
sbt -Dsbt.override.build.repos=true compile
如果镜像生效,sbt -v 里能看到仓库地址变化,改完记得清一下旧缓存:
%USERPROFILE%.ivy2cache%USERPROFILE%.sbtboot
代理和超时参数怎么加
公司网络需要代理时,把 JVM 参数写进 %USERPROFILE%.jvmopts:
-Dhttp.proxyHost=proxy.company.com -Dhttp.proxyPort=8080 -Dhttps.proxyHost=proxy.company.com -Dhttps.proxyPort=8080 -Xmx2G
不要把代理密码硬编码进文件,证书拦截场景需要导入企业根证书,再通过 -Djavax.net.ssl.trustStore 指定信任库,改完用 sbt -v 和 sbt update 验证。
sbt 与 Maven 配置区别到底在哪
行业共识认为,sbt 更贴合 Scala 生态的增量编译和交互式任务,Maven 的优势在通用性和团队熟悉度,两者核心差异可以看这张表:
| 对比项 | sbt | Maven |
|---|---|---|
| 主配置文件 | build.sbt |
pom.xml |
| 依赖声明 | libraryDependencies |
<dependencies> |
| 作用域表达 | % Test、% Provided |
<scope>test</scope> |
| 多模块组织 | lazy val、dependsOn、aggregate |
<modules>、<parent> |
| 增量编译体验 | 多数情况下较顺 | 依赖插件和项目结构 |
| 学习曲线 | 较陡,DSL 灵活 | 较平缓,XML 结构固定 |
从 Maven 迁到 sbt 要改哪些
pom.xml的groupId、artifactId、version分别对应organization、name、version。<scope>test</scope>改成% Test。- 父工程聚合改成
lazy val root = (project in file(".")).aggregate(...)。 - 插件配置从
<build><plugins>迁到project/plugins.sbt和build.sbt。
业内专家指出,迁移前先确认 CI 是否依赖 Maven 的生命周期命令,企业内训或迁移服务的报价差异较大,先看服务范围是否包含 CI 改造和私有仓库配置,再比较价格更实际。
sbt 多模块项目配置步骤
目录结构先定好
multi-demo/
├── build.sbt
├── project/
│ ├── build.properties
│ └── plugins.sbt
├── core/
│ └── src/main/scala
└── app/
└── src/main/scala
用 lazy val 串起模块依赖
lazy val commonSettings = Seq(
scalaVersion := "2.13.14",
organization := "com.example",
version := "0.1.0"
)
lazy val core = (project in file("core"))
.settings(commonSettings)
.settings(name := "core")
lazy val app = (project in file("app"))
.dependsOn(core)
.settings(commonSettings)
.settings(name := "app")
lazy val root = (project in file("."))
.aggregate(core, app)
.settings(commonSettings)
.settings(name := "root")
常用命令:
sbt projects看模块列表。sbt app/compile只编译 app。sbt "core/test"只跑 core 的测试。sbt root/compile通过聚合模块统一编译。
插件和打包别混在一起
project/plugins.sbt 里加打包插件,

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.2.0")
build.sbt 里再写入口类和包名:
assembly / mainClass := Some("com.example.Main")
assembly / assemblyJarName := "app.jar"
执行 sbt assembly 生成可运行包,插件版本以插件发布页为准,不要只看博客里的旧版本号。
CI 里怎么固定参数
CI 命令建议写成非交互模式,避免卡在等待输入:
sbt -batch -Dsbt.override.build.repos=true clean test
再把 JAVA_HOME、sbt.version、镜像仓库文件纳入版本管理或构建镜像,构建环境越一致,sbt 配置的排错成本越低。
sbt 配置不是背命令,而是把版本、仓库、模块边界三件事写清楚,先把这三处固定下来,再谈插件和性能优化,团队协作会稳很多。
Q&A:sbt 配置常见问题
sbt 配置国内镜像后还是慢怎么办?
先确认 -Dsbt.override.build.repos=true 是否真的生效,用 sbt -v 看仓库地址,再清 ~/.ivy2/cache 和 ~/.sbt/boot 后重试,仍然慢时检查代理、DNS 和证书拦截,别只盯着镜像地址。
sbt 配置文件和 Maven 的 pom.xml 能共存吗?
可以共存,但不要让两个构建工具同时写同一套产物,CI 只选一个入口,团队约定主构建工具,sbt 读 build.sbt,Maven 读 pom.xml,目录里同时存在时容易在打包和发布阶段互相覆盖。
sbt 配置需要付费吗?
sbt 本身是开源工具,下载和使用不收取授权费,付费通常来自企业内训、迁移咨询、私有仓库或 CI 基础设施,价格取决于项目规模和改造范围,公开报价差异较大,sbt 的授权成本为零,成本主要落在人力和基础设施上。
