# Squants makes the unit part of the type, not a comment

> Squants is the TypeLevel Scala library for quantities, units of measure and dimensional analysis, where energy and power are different types so adding them does not compile. It is built for JVM, Scala.js and native, and its README still advertises version 1.6.0 while the newest release tag is 1.8.3 from 2021.

**typelevel/squants** — The Scala API for Quantities, Units of Measure and Dimensional Analysis

- Repository: https://github.com/typelevel/squants
- Website: http://typelevel.org/squants/
- Stars: 930 · Forks: 121
- Language: Scala
- License: Apache-2.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/typelevel-squants

## The trouble with doubles in a domain full of units

Squants is described as the Scala API for quantities, units of measure and dimensional analysis, a framework of data types and a domain specific language for representing quantities, their units of measure and their dimensional relationships.

The README starts from the problem it solves, and the problem is specific. When developers build programs that perform dimensional analysis they reach for a basic numeric type, usually Double. That compiles, and it quietly permits nonsense.

The worked example is energy against power. A load in kW and an energy amount in MWh can be added together in a program, because both are doubles. The README is careful about the two separate errors this hides: the two values measure different dimensions, since kWh measures an amount of energy while kW measures the rate at which energy is produced or used, and the scale prefixes differ too, Mega against Kilo.

The consequence is stated plainly: because the code compiles, detection of these errors is pushed further into the development cycle. Squants moves that detection to compile time, and the README attributes that shift to the stronger types rather than to any runtime check.

All types in the library are described as immutable and thread-safe, which matters for a type that ends up in shared domain code.

## Only quantities with the same dimension may be combined

The core rule is one line in the README: only quantities with the same dimensions may be compared, equated, added or subtracted.

The library enforces it with distinct types per dimension. Energy and Power are separate types in the squants.energy package, and each has its own unit constructors.

```scala
scala> val load: Power = Kilowatts(1.2)
load: squants.energy.Power = 1.2 kW

scala> val energy: Energy = KilowattHours(23.0)
energy: squants.energy.Energy = 23.0 kWh
```

With those two values in scope, the invalid operation fails at compile time.

```scala
scala> val sum = load + energy
<console>:16: error: type mismatch;
 found   : squants.energy.Energy
 required: squants.energy.Power
       val sum = load + energy
                        ^
```

Note the second effect visible in the error. The prefixes no longer need to be carried in the variable name, because the type says what the value is and the unit constructor says what scale it is in. The README calls this out as the other half of the improvement over doubles.

The trade-off is that every value crossing your API boundary becomes a typed quantity rather than a number, so adoption is a type-level refactor of the affected code, not a drop-in replacement.

## Scale conversion happens inside comparisons, so kW and MW add up

Different units of the same dimension interoperate, and the conversion is applied for you.

```scala
scala> import squants.energy.{Kilowatts, Megawatts, Power}

scala> val load1: Power = Kilowatts(12)
load1: squants.energy.Power = 12.0 kW

scala> val load2: Power = Megawatts(0.023)
load2: squants.energy.Power = 0.023 MW

scala> val sum = load1 + load2
sum: squants.energy.Power = 35.0 kW

scala> sum == Kilowatts(35)
res0: Boolean = true

scala> sum == Megawatts(0.035) // comparisons automatically convert scale
res1: Boolean = true
```

Two things happen here. Adding two powers of different scales yields a value in a normalised unit, and equality ignores scale, so a value equal to 35 kW also equals 0.035 MW.

That last point is the one to think about before adopting. Scale-insensitive equality is convenient and it is also a place where a bug can hide, because a value that should have been rounded or rejected at a boundary is accepted instead. The library does the conversion, and the README does not describe any rounding or tolerance policy for comparisons, so any such rule would have to live in your own code.

The same care applies to the dimensionless result produced by dividing two quantities of the same dimension, which returns a plain Double rather than a typed value.

## Multiplication and division derive new dimensions at the type level

Beyond matching units, Squants lets you derive new quantities from existing ones, and the README calls dimensionally correct type conversions a key feature.

The mechanism is stated directly: conversions are implemented by defining relationships between quantity types using the * and / operators. So a Power multiplied by a Time yields an Energy, and the compiler knows that.

```scala
scala> val load = Kilowatts(1.2)
load: squants.energy.Power = 1.2 kW

scala> val time = Hours(2)
time: squants.time.Time = 2.0 h

scala> val energyUsed = load * time
energyUsed: squants.energy.Energy = 2400.0 Wh
```

A ratio of two quantities of the same dimension collapses to a dimensionless Double, as the README shows with Days(1) / Hours(3) returning 8.0.

```scala
scala> val ratio = Days(1) / Hours(3)
ratio: Double = 8.0
```

This is the part of the library that goes beyond a units table. Because the relationships are expressed in the type system, the expression itself documents the physical relationship, Power equals Energy divided by Time, rather than a comment stating it.

The cost is that multiplication and division on quantities are meaningful in ways they are not for plain numbers, which means code that treats quantities generically has to be written generically rather than with the arithmetic habits you have for Double.

## jvm/, js/, native/ and shared/ is how the library spans three platforms

The repository layout tells you the platform story before the README does. The top level holds .github/, .gitignore, .sbtopts, LICENSE, README.md, build.sbt, js/, jvm/, native/, project/ and shared/.

The split into js, jvm, native and shared is the standard cross-project arrangement, and it means Squants is not JVM only. The README backs that up by noting that Scala.js is supported on versions 0.6.31 and 1.0.0-RC1, and the API documentation badge points at the 2.13 artefact.

The supported Scala versions are spelled out in the same paragraph. Beginning with the 0.4.x series both Scala 2.10 and 2.11 builds are available, and beginning with the 1.x series there are Scala 2.11, 2.12 and 2.13 builds. The Scala.js support line names specific versions rather than a range, which suggests that the cross-build matrix is not uniform across the whole history.

A library like this earns its keep precisely when the same domain code has to run on a server and in a browser, so the platform matrix is a feature rather than packaging overhead. It is also a compatibility constraint, since your build has to line up with one of the published cross versions.

## The README advertises 1.6.0 while the newest tag is 1.8.3

The version information in the repository is inconsistent, and it is worth resolving before you depend on it.

The Current Versions section of the README says the current release is 1.6.0 and the development build is 1.7.0-SNAPSHOT, with links to the Sonatype hosted javadoc for both. The install instructions repeat those numbers.

The release tags tell a later story. The recent releases are v1.7.2 on 2021-03-08, v1.8.2 on 2021-08-12 and v1.8.3 on 2021-08-26. So the tags run ahead of the README, and the README itself carries a note that it reflects the feature set in the branch it can be found in, with a pointer to the release history wiki and to the README of a specific version for feature availability.

The repository hosting is Sonatype, and the artefacts are published under the org.typelevel group with the squants name and a Scala suffix, squants_2.13 in the documentation links. Build services are provided by Travis CI.

On maintenance, the repository is not archived and the last push was on 2026-09-03, so the code is still moving, but the newest published release tag is more than five years old. That combination, a repository with recent commits and a published artefact set that stops in 2021, is the single most important fact for anyone planning to adopt Squants.

The licence field on the repository says Apache-2.0, which is permissive, with the usual attribution and patent grant terms.

## Adding Squants to a build, and trying it in the REPL

The dependency coordinates are the whole installation story. For an SBT project the README gives the release line first.

```scala
"org.typelevel"  %% "squants"  % "1.6.0"
```

Or the development build.

```scala
"org.typelevel"  %% "squants"  % "1.7.0-SNAPSHOT"
```

For Maven the coordinates are spelled out with the artifact named for the Scala binary version, which is 2.11 in the README's example.

```xml
<dependency>
    <groupId>org.typelevel</groupId>
    <artifactId>squants_2.11</artifactId>
    <version>1.6.0</version>
</dependency>
```

To try it interactively without wiring it into a project, the README tells you to clone the repository and start the console for the JVM project.

```bash
git clone https://github.com/typelevel/squants
cd squants
sbt squantsJVM/console
```

One more signal about how the library is meant to be used: the README lists third-party integrations for configuration handling, naming PureConfig and Ciris, and invites a pull request to add more. A dimensional type that cannot be read from a configuration file is not much use, so those integrations matter more to adoption than the arithmetic does.

## Conclusion

Squants fits a Scala team whose domain has units that must not be mixed, such as energy, power, time or space, and who want the mistake caught by the compiler rather than by a reviewer. It does not fit a codebase where quantities are plain doubles with unit-suffixed names, because introducing Squants means changing the types across every call site, and it does not fit a project that needs Scala 3. Before adopting it, check which Scala versions your build targets against the 2.11, 2.12 and 2.13 artefacts, and note that the last push was on 2026-09-03 while the newest published tag is v1.8.3 from 2021-08-26, so pin your version deliberately.

## FAQ

### Which Scala versions does Squants support?

The README states that beginning with the 1.x series there are Scala 2.11, 2.12 and 2.13 builds, and that Scala.js is supported on versions 0.6.31 and 1.0.0-RC1. Maven coordinates are published per binary version, such as squants_2.11.

### How do I add Squants to an SBT build?

Add the dependency "org.typelevel" %% "squants" % "1.6.0" for the release, or the 1.7.0-SNAPSHOT development build. Repository hosting is provided by Sonatype, and the documentation for the current release is published there.

### Does Squants convert between units automatically?

Yes. The README states that the library type checks operations at compile time and automatically applies scale and type conversions at run time, so adding Kilowatts to Megawatts yields a normalised value and comparisons convert scale automatically.

## Sources

- [License: Apache-2.0](https://github.com/typelevel/squants/blob/master/LICENSE)
- [Project website](http://typelevel.org/squants/)
- [README](https://github.com/typelevel/squants/blob/master/README.md)
- [Releases](https://github.com/typelevel/squants/releases)
- [typelevel/squants on GitHub](https://github.com/typelevel/squants)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/typelevel-squants
