Skip to main content
This guide covers how to configure your project for publishing, generate POM files, and publish artifacts to repositories.

Basic Publishing Configuration

Configure the essential metadata for publishing:
build.sbt
organization := "com.example"
name := "my-library"
version := "1.0.0"

// Project metadata
description := "A useful Scala library"
licenses := Seq("Apache-2.0" -> url("https://www.apache.org/licenses/LICENSE-2.0"))
homepage := Some(url("https://github.com/example/my-library"))

// SCM information
scmInfo := Some(
  ScmInfo(
    url("https://github.com/example/my-library"),
    "scm:[email protected]:example/my-library.git"
  )
)

// Developers
developers := List(
  Developer(
    id = "johndoe",
    name = "John Doe",
    email = "[email protected]",
    url = url("https://github.com/johndoe")
  )
)
These metadata fields are included in the generated POM file and displayed on Maven Central.

Publishing Style

Choose between Maven and Ivy publishing:
build.sbt
// Maven-style publishing (recommended for most projects)
publishMavenStyle := true

// Ivy-style publishing
publishMavenStyle := false
Use Maven-style publishing (publishMavenStyle := true) for publishing to Maven Central or other Maven repositories.

Publish Destination

Configure where to publish:
publishTo := {
  val nexus = "https://s01.oss.sonatype.org/"
  if (isSnapshot.value)
    Some("snapshots" at nexus + "content/repositories/snapshots")
  else
    Some("releases" at nexus + "service/local/staging/deploy/maven2")
}

Publishing Tasks

sbt provides several publishing tasks:
# Publish to the repository defined in publishTo
sbt publish

# Publish to local Ivy repository (~/.ivy2/local)
sbt publishLocal

# Publish to local Maven repository (~/.m2/repository)
sbt publishM2

# Generate POM file only
sbt makePom
1

Test locally

sbt publishLocal
Publishes to your local Ivy cache for testing.
2

Test with Maven

sbt publishM2
Publishes to your local Maven repository.
3

Publish to remote

sbt publish
Publishes to the configured remote repository.

Credentials

Configure credentials for publishing to private repositories:
credentials += Credentials(
  "Sonatype Nexus Repository Manager",
  "s01.oss.sonatype.org",
  "username",
  "password"
)
Credentials file format:
~/.sbt/sonatype_credentials
realm=Sonatype Nexus Repository Manager
host=s01.oss.sonatype.org
user=your-username
password=your-password

POM Customization

Extra POM Elements

Add custom XML to the generated POM:
build.sbt
pomExtra := 
  <properties>
    <info.apiURL>https://api.example.com</info.apiURL>
  </properties>

POM Post-Processing

Transform the generated POM:
build.sbt
import scala.xml._
import scala.xml.transform._

pomPostProcess := { (node: Node) =>
  new RuleTransformer(new RewriteRule {
    override def transform(node: Node): Seq[Node] = node match {
      case e: Elem if e.label == "dependency" && 
        (e \\ "groupId").text == "bad-dependency" =>
        NodeSeq.Empty
      case _ => node
    }
  }).transform(node).head
}

Repository Filtering

Control which repositories appear in the POM:
build.sbt
// Include all repositories
pomAllRepositories := true

// Filter repositories
pomIncludeRepository := { repo: MavenRepository =>
  repo.root.startsWith("https://")
}
Be careful when including custom repositories in published POMs as it can affect dependency resolution for users.

Publishing Artifacts

Control What Gets Published

build.sbt
// Publish main artifact
Compile / packageBin / publishArtifact := true

// Publish test artifact
Test / packageBin / publishArtifact := false

// Publish sources
Compile / packageSrc / publishArtifact := true

// Publish documentation
Compile / packageDoc / publishArtifact := true

Custom Artifacts

Define custom artifacts to publish:
build.sbt
artifacts ++= Seq(
  Artifact(
    name = "my-library",
    `type` = "zip",
    extension = "zip",
    classifier = "assets"
  )
)

packagedArtifacts += {
  val assetsZip = (Compile / target).value / "my-library-assets.zip"
  // Create the zip...
  artifacts.value.head -> assetsZip
}

Cross-Publishing

Publish for multiple Scala versions:
build.sbt
crossScalaVersions := Seq("2.13.12", "3.3.1")
# Publish for all Scala versions
sbt +publish

# Publish locally for all versions
sbt +publishLocal

# Publish for specific version
sbt ++2.13.12 publish

sbt Plugin Publishing

For sbt plugins, additional configuration is needed:
build.sbt
sbtPlugin := true

// The sbt version to compile against
pluginCrossBuild / sbtVersion := "2.0.0-M2"

// Publish legacy Maven-style (for compatibility)
sbtPluginPublishLegacyMavenStyle := true
# Publish plugin for multiple sbt versions  
sbt +publish

Signing Artifacts

Sign your artifacts for publishing to Maven Central:
project/plugins.sbt
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.2.1")
# Use PGP key from keyring
sbt publishSigned

# Or configure key
sbt set Global / usePgpKeyHex("DEADBEEF")
Maven Central requires signed artifacts. Use sbt-pgp plugin for signing.

Staging and Release

For Sonatype/Maven Central, use a staging workflow:
project/plugins.sbt
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.10.0")
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.2.1")
# Publish signed artifacts to staging
sbt publishSigned

# Close and release staging repository
sbt sonatypeBundleRelease

Version Management

Snapshot Versions

build.sbt
version := "1.0.0-SNAPSHOT"

isSnapshot := version.value.endsWith("-SNAPSHOT")
Snapshots are published to snapshot repositories and can be overwritten.

Release Versions

build.sbt
version := "1.0.0"
Release versions are immutable once published to Maven Central.

Version Scheme

Declare your versioning scheme:
build.sbt
versionScheme := Some("early-semver")
// Options: "early-semver", "pvp", "semver-spec", "strict"
Declaring versionScheme helps dependency resolution understand version compatibility.

Publishing Workflow

1

Configure metadata

Set all required fields: organization, name, version, licenses, developers, scmInfo.
2

Test locally

sbt publishLocal
3

Configure credentials

Add credentials for your target repository.
4

Set publish destination

Configure publishTo for your repository.
5

Sign artifacts (for Maven Central)

Use sbt-pgp to sign your artifacts.
6

Publish

sbt publish

Best Practices

1

Complete metadata

Always provide complete metadata: organization, licenses, SCM info, and developers.
2

Use semantic versioning

Follow semantic versioning and declare your versionScheme.
3

Publish sources and docs

Always publish source and documentation JARs for better IDE integration.
4

Test before publishing

Use publishLocal or publishM2 to test your artifacts before publishing.
5

Keep credentials secure

Store credentials in files outside your repository or use environment variables.
6

Sign releases

Sign all release artifacts, especially for Maven Central.
7

Cross-publish libraries

For libraries, publish for multiple Scala versions using crossScalaVersions.

Build docs developers (and LLMs) love