Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool

Scala JSON Formatter Libraries and Approaches

Working with JSON is ubiquitous in modern software development, especially in backend services and APIs. While parsing JSON strings into Scala data structures and serializing Scala data structures back into JSON strings are common tasks, controlling the formatting of the output JSON is equally important. Formatting affects readability, debugging, and the ability to easily compare different JSON payloads (diffing).

Why Format JSON?

Formatted JSON, often referred to as "pretty-printed" JSON, includes whitespace (spaces, tabs, newlines) to make the structure clear and easy for humans to read. Compact JSON, on the other hand, removes all unnecessary whitespace to minimize size, which is ideal for transmission over a network.

Key reasons for formatting:

  • Readability: Makes complex JSON structures understandable at a glance.
  • Debugging: Easier to pinpoint issues in JSON payloads when the structure is clear.
  • Diffing: Comparing two versions of a JSON object is significantly easier with consistent indentation and line breaks.
  • Interoperability: While whitespace is ignored by parsers, some tools or manual processes might benefit from consistent formatting.

Scala offers several powerful libraries for handling JSON, and most of them provide robust capabilities for controlling the output format. Let's look at some of the most popular ones and how they approach formatting.

Popular Scala JSON Libraries and Formatting

Circe

Circe is a popular, purely functional JSON library for Scala, built on top of Cats and Cats-Effect. It provides excellent encoding, decoding, and manipulation capabilities. Formatting is straightforward.

Circe Formatting Example (pretty printing with 2 spaces):

import io.circe._
import io.circe.syntax._ // Provides .asJson

// Sample data structure
case class User(name: String, age: Int, tags: List[String])

val user = User("Alice", 30, List("scala", "json", "circe"))

// Encode to Json value
val userJson: Json = user.asJson

// Pretty print with 2-space indentation
val prettyJsonString: String = userJson.spaces2

// Pretty print with 4-space indentation
// val prettyJsonString: String = userJson.spaces4

// Compact printing (no extra whitespace)
val compactJsonString: String = userJson.noSpaces

println("Pretty (2 spaces):")
println(prettyJsonString)

println("\nCompact:")
println(compactJsonString)

Output Example:

Pretty (2 spaces):
{
  "name" : "Alice",
  "age" : 30,
  "tags" : [
    "scala",
    "json",
    "circe"
  ]
}

Compact:
{"name":"Alice","age":30,"tags":["scala","json","circe"]}

Circe provides simple methods like .spaces2, .spaces4, and .noSpaces directly on the Json value. You can also create a custom printer using Printer.

Play JSON

Part of the Play Framework ecosystem, Play JSON is another widely used library. It provides an immutable tree representation of JSON and convenient macros for mapping between JSON and Scala case classes. It also offers built-in formatting options.

Play JSON Formatting Example:

import play.api.libs.json._

// Sample data structure (needs implicit Writes/Reads)
case class Product(id: Long, name: String, price: BigDecimal)

// Define implicit Writes to convert Product to Json
implicit val productWrites: Writes[Product] = Json.writes[Product]

val product = Product(101, "Laptop", BigDecimal(1200.50))

// Convert to Json value
val productJson: JsValue = Json.toJson(product)

// Pretty print
val prettyJsonString: String = Json.prettyPrint(productJson)

// Compact print
val compactJsonString: String = Json.stringify(productJson)

println("Pretty:")
println(prettyJsonString)

println("\nCompact:")
println(compactJsonString)

Output Example:

Pretty:
{
  "id" : 101,
  "name" : "Laptop",
  "price" : 1200.50
}

Compact:
{"id":101,"name":"Laptop","price":1200.50}

Play JSON uses Json.prettyPrint(jsValue) for formatted output and Json.stringify(jsValue) for compact output.

uPickle

uPickle is a lightweight, fast, and popular pickling library for Scala, primarily focused on serialization/deserialization between Scala objects and common data formats like JSON. Its formatting capabilities are controlled during the writing process.

uPickle Formatting Example:

import upickle.default._

// Sample data structure (uPickle can often derive ReadWriter implicitly)
case class Config(theme: String, retries: Int, enabled: Boolean)
implicit val configRW: ReadWriter[Config] = macroRW // Derive ReadWriter

val config = Config("dark", 3, true)

// Pretty print with 2-space indentation
val prettyJsonString: String = write(config, indent = 2)

// Pretty print with 4-space indentation
// val prettyJsonString: String = write(config, indent = 4)

// Compact print (default)
val compactJsonString: String = write(config)

println("Pretty (indent=2):")
println(prettyJsonString)

println("\nCompact:")
println(compactJsonString)

Output Example:

Pretty (indent=2):
{
  "theme": "dark",
  "retries": 3,
  "enabled": true
}

Compact:
{"theme":"dark","retries":3,"enabled":true}

With uPickle, you control formatting using the indent parameter in the write function. An indentation level of 0 or negative results in compact output (which is also the default).

Jackson Scala Module

For projects integrating with Java ecosystems or relying on the vast features of the Jackson library, the Jackson Scala Module provides Scala-friendly serialization/deserialization. Formatting is typically handled via Jackson's ObjectMapper configuration.

Jackson Scala Module Formatting Example:

import com.fasterxml.jackson.databind.{ObjectMapper, SerializationFeature}
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter

// Sample data structure
case class Item(name: String, quantity: Int)

val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)

val item = Item("Widget", 5)

// Convert to JSON Node (optional intermediate step)
// val itemNode = mapper.valueToTree[JsonNode](item)

// Pretty print using enable(SerializationFeature.INDENT_OUTPUT)
mapper.enable(SerializationFeature.INDENT_OUTPUT)
val prettyJsonString: String = mapper.writeValueAsString(item)

// You can also configure the printer directly
// mapper.setDefaultPrettyPrinter(new DefaultPrettyPrinter()) // Use default
// val prettyJsonString: String = mapper.writer(new DefaultPrettyPrinter()).writeValueAsString(item)

// Compact print (default)
mapper.disable(SerializationFeature.INDENT_OUTPUT) // Ensure indentation is off
val compactJsonString: String = mapper.writeValueAsString(item)


println("Pretty:")
println(prettyJsonString)

println("\nCompact:")
println(compactJsonString)

Output Example:

Pretty:
{
  "name" : "Widget",
  "quantity" : 5
}

Compact:
{"name":"Widget","quantity":5}

Jackson's approach is more configuration-driven via the ObjectMapper. Enabling SerializationFeature.INDENT_OUTPUT provides default pretty-printing, and you can configure or provide a custom PrettyPrinter for more control.

Custom Formatting and Advanced Options

While the standard pretty-printers provided by libraries are sufficient for most cases, you might encounter scenarios requiring more control, such as:

  • Sorting keys alphabetically for deterministic output (great for diffing).
  • Customizing indentation characters (spaces vs. tabs) or count.
  • Controlling spacing around colons and commas.
  • Excluding null fields.

Most libraries offer ways to customize the printer behavior.

  • Circe: The io.circe.Printer class allows fine-grained control over whitespace, key sorting, and more. You create a Printer instance and call its print(jsonValue) method.
  • Play JSON: While prettyPrint is fixed, you could potentially traverse the JsValue tree and build a string manually or use a helper library if extensive customization is needed, though its built-in options are less flexible than Circe's Printer.
  • uPickle: The write method offers the indent parameter, but more advanced customization like key sorting might require manual processing or different serialization logic before writing.
  • Jackson: Jackson's PrettyPrinter interface (like DefaultPrettyPrinter) is highly configurable. You can extend it or configure aspects like indentation, separators, and object/array formatting. Key sorting can be enabled via SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS.

Choosing the Right Approach

The best library or approach depends largely on your project's existing dependencies, performance requirements, and whether you prefer a more functional or imperative style.

  • If you're already using Play Framework or prefer its ecosystem, Play JSON is a natural fit.
  • For purely functional programming, excellent type safety, and fine-grained control over encoding/decoding/formatting, Circe is a top choice. Its Printer is very powerful for custom formatting.
  • If speed and simplicity are paramount, and you don't need extensive custom formatting beyond indentation, uPickle is a strong contender.
  • In a Java-heavy environment or if you need advanced features and control offered by Jackson, the Jackson Scala Module is a solid option, bringing Jackson's powerful features (including highly customizable pretty-printing) to Scala.

For most pretty-printing needs, the built-in methods (.spaces2, Json.prettyPrint, write(..., indent=...), SerializationFeature.INDENT_OUTPUT) are more than adequate. Dive into custom Printer configurations only when specific formatting rules are required (like key sorting or unique indentation styles).

Conclusion

Scala offers excellent choices for working with and formatting JSON data. Libraries like Circe, Play JSON, uPickle, and the Jackson Scala Module each provide straightforward ways to generate both compact and human-readable "pretty-printed" JSON output. Understanding the formatting options available in your chosen library allows you to produce JSON that is not only valid but also easy to read, debug, and manage, greatly improving the developer experience when dealing with JSON payloads in your Scala applications.

Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool