sbt-war is an sbt plugin for packaging and running .war files.
sbt-war is formerly known as xsbt-web-plugin. For documentation and source code of prior versions, browse this repository from the desired git tag. The most recent prior version is 4.2.5.
- sbt 1.x and up
- Scala 2.12.x and up
- Submit a question, bug report, or feature request as a new GitHub issue
- Look for earldouglas in the
#sbt
channel on the Scala Discord server
$ sbt new earldouglas/sbt-war.g8
name [My Web Project]: hello sbt-war
Template applied in ./hello-sbt-war
$ cd hello-sbt-war/
$ sbt
> webappStart
$ curl localhost:8080/hello
<h1>Hello, world!</h1>
> webappStop
Create a new empty project:
$ mkdir myproject
$ cd myproject
Set up the project structure:
$ mkdir project
$ mkdir -p src/main/scala/mypackage
Configure sbt:
project/build.properties:
sbt.version=1.10.2
project/plugins.sbt:
addSbtPlugin("com.earldouglas" % "sbt-war" % "5.0.0-M2")
build.sbt:
scalaVersion := "3.5.1"
libraryDependencies += "jakarta.servlet" % "jakarta.servlet-api" % "6.0.0" % Provided
enablePlugins(SbtWar)
Add a servlet:
src/main/scala/mypackage/MyServlet.scala:
package mypackage
import jakarta.servlet.annotation.WebServlet
import jakarta.servlet.http.HttpServlet
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
@WebServlet(urlPatterns = Array("/hello"))
class MyServlet extends HttpServlet:
override def doGet(
req: HttpServletRequest,
res: HttpServletResponse
): Unit =
res.setContentType("text/html")
res.setCharacterEncoding("UTF-8")
res.getWriter.write("""<h1>Hello, world!</h1>""")
Run it from sbt with webappStart
:
$ sbt
> webappStart
$ curl localhost:8080/hello
<h1>Hello, world!</h1>
Stop it with webappStop
:
> webappStop
Create a .war file with package
:
> package
Key | Type | Default | Notes |
---|---|---|---|
webappResources |
Map[String,File] |
src/main/webapp | Static files (HTML, CSS, JS, images, etc.) to serve directly |
webappClasses |
Map[String,File] |
project classes | .class files to copy into the WEB-INF/classes directory |
webappLib |
Map[String,File] |
project libs | .jar files to copy into the WEB-INF/lib directory |
webappRunnerVersion |
String |
"10.1.28.0" |
The version of com.heroku:webapp-runner to use for running the webapp |
webappComponentsRunnerVersion |
String |
"10.1.28.0-M1" |
The version of com.earldouglas:webapp-components-runner to use for running the webapp |
webappPort |
Int |
8080 |
The local container port to use when running with webappStart |
warPort |
Int |
8080 |
The local container port to use when running with warStart |
webappForkOptions |
ForkOptions |
Buffered output | Options for the forked JVM used when running with webappStart |
warForkOptions |
ForkOptions |
Buffered output | Options for the forked JVM used when running with warStart |
Key | Notes |
---|---|
webappStart |
Starts a local container, serving content directly from project sources |
webappJoin |
Blocks until the container shuts down |
webappStop |
Shuts down the container |
warStart |
Starts a local container, serving content from the packaged .war file |
warJoin |
Blocks until the container shuts down |
warStop |
Shuts down the container |
Settings and commands that begin with war
apply to the packaged .war
file, which includes resources, classes, and libraries. The development
cycle can be sped up by serving resources, classes, and libraries
directly from source, avoiding the overhead of packaging a
.war file.
Use the webapp
prefix in place of war
to skip packaging, and run the
container directly from source:
> webappStart
Webapp resources are the various static files, deployment descriptors, etc. that go into a .war file.
The webappResources
setting is a mapping from destination to source of
these files. The destination is a path relative to the contents of the
.war file. The source is a path on the local filesystem.
By default, everything in src/main/webapp is included.
For example, given the following .war file:
myproject.war
├── index.html
├── styles/
│ └── theme.css
├── WEB-INF/
│ └── web.xml
└── META-INF/
└── MANIFEST.MF
The webappResources
mapping would look like this:
"index.html" -> File(".../src/main/webapp/index.html")
"styles/theme.css" -> File(".../src/main/webapp/styles/theme.css")
"WEB-INF/web.xml" -> File(".../src/main/webapp/WEB-INF/web.xml")
To use a different directory, e.g. src/main/WebContent:
webappResources :=
(Compile / sourceDirectory)
.map(_ / "WebContent")
.map(WebappComponents.getResources)
Manifest attributes of the .war file can be configured via
packageOptions
:
sbt.Keys.`package` / packageOptions +=
Package.ManifestAttributes(
java.util.jar.Attributes.Name.SEALED -> "true"
)
By default, project classes are copied into the WEB-INF/classes
directory of the .war file. To package them in a .jar file in the
WEB-INF/lib directory instead, set exportJars
:
exportJars := true
See "Configure packaging" in the sbt documentation for additional information.
By default, all runtime dependencies are copied into the WEB-INF/lib directory.
To use a dependency at compile time but exclude it from the .war file,
set its scope to Provided
:
libraryDependencies += "foo" % "bar" % "1.0.0" % Provided
By default, Webapp Runner
10.1.x is used to run the .war file in a forked JVM. To use a different
version, set webappRunnerVersion
:
webappRunnerVersion := "9.0.93.0"
By default, Webapp Components
Runner 10.1.x
is used to run the webapp in a forked JVM. To use a different version,
set webappComponentsRunnerVersion
:
webappComponentsRunnerVersion := "9.0.93.0.0"
By default, the container runs on port 8080. To use a different port,
set warPort
/webappPort
:
warPort := 9090
webappPort := 9090
To set environment variables, system properties, and more for the
forked container JVM, set a
ForkOptions
instance via warForkOptions
.
For example: to attach a debugger, set -Xdebug
and -Xrunjdwp
:
build.sbt:
warForkOptions :=
ForkOptions()
.withRunJVMOptions(
Seq(
"-Xdebug",
"-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000"
)
)
To set environment variables, system properties, and more for the
forked container JVM, set a
ForkOptions
instance via webappForkOptions
.
For example: to attach a debugger, set -Xdebug
and -Xrunjdwp
:
build.sbt:
webappForkOptions :=
ForkOptions()
.withRunJVMOptions(
Seq(
"-Xdebug",
"-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000"
)
)
> webappStart
> warStart
These can be used to block sbt while the container is running:
$ sbt webappStart webappJoin
$ sbt warStart warJoin
This is useful for running sbt in production (e.g. in a Docker container), if you're into that kind of thing.
These can be used to stop the running container:
> webappStop
> warStop