Skip to main content

Modular Building Blocks for Modern Scala Applications

The philosophy is simple: use what you need, nothing more. Each block is independently useful and designed to compose with other blocks or your existing code.

Get startedGitHub

Works with ZIO 2.x · Cats Effect 3.x · Kyo · Ox · Akka · Plain Scala

01   Principles

Use What You Need, Nothing More

  1. 01 Zero Lock-In No dependency on ZIO, Cats Effect, or any other effect system.
  2. 02 Modular Each block is a separate artifact.
  3. 03 Cross-Platform Most blocks cross-build for JVM and Scala.js on Scala 2.13 and 3.x. Adopt Scala 3 on your timeline.
  4. 04 High Performance Implementations that avoid boxing, minimize allocations, and use platform-specific features where they pay off.
  5. 05 Type Safety Scala's type system carries the correctness guarantees, without runtime overhead.

02   Deep Dives

Four Blocks, in Code

Schema

The Schema block brings dynamic-language productivity to statically-typed Scala. Define your data types once, and derive codecs, validators, optics, and more automatically.

Installation

libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.56"

The Problem

In statically-typed languages, you often maintain separate codec implementations for each data format (JSON, Avro, Protobuf, etc.). Meanwhile, dynamic languages handle data effortlessly:

// JavaScript: one line and done
const data = await res.json();

The Solution

ZIO Blocks Schema derives everything from a single schema definition:

case class Person(name: String, age: Int)
object Person {
implicit val schema: Schema[Person] = Schema.derived
}
// Derive codecs for any format:
val jsonCodec = Schema[Person].derive(JsonFormat) // JSON
val avroCodec = Schema[Person].derive(AvroFormat) // Avro
val toonCodec = Schema[Person].derive(ToonFormat) // TOON (LLM-optimized)
val msgpackCodec = Schema[Person].derive(MessagePackFormat) // MessagePack
val thriftCodec = Schema[Person].derive(ThriftFormat) // Thrift

One Schema, Many Formats

  • JSON
  • Avro
  • BSON
  • CSV
  • MessagePack
  • Thrift
  • TOON
  • XML
  • YAML
  • Your First Schema — a getting-started tutorial: describe a type once, round-trip it through JSON, and read decode errors
  • Evolve Your Data — a tutorial that validates incoming data with Into, converts between versions with As, and renames a stored field with a compile-checked Migration
  • One Type, Many Formats — a tutorial that exports one catalog as JSON, YAML, XML, TOON, MessagePack, Avro and CSV from the same schema
  • How to Encode and Decode Records with Avro — a how-to guide that writes the .avsc schema for a sealed trait, streams Avro records, maps each Scala type to its Avro type, and reads the bytes with Apache Avro
  • How to Store Case Classes in MongoDB — a how-to guide that derives a BSON codec, uses ObjectId as the _id, chooses how sealed traits and options are stored, and inserts and queries tickets with the MongoDB Java driver
  • Schema reference — the full API surface, from Reflect and Binding through optics, validation, and schema evolution
  • Migrating from ZIO Schema — a step-by-step port from ZIO Schema 1.x
  • Coming from circe, zio-json or jsoniter-scala — move JSON codecs to one derived Schema, keeping field names, discriminators and custom formats

Scope

Compile-time verified resource safety for synchronous Scala code. Scope prevents resource leaks at compile time by tagging values with an unnameable type-level identity—values allocated in a scope can only be used within that scope. Child scope values cannot escape to parent scopes, enforced by both the abstract scope-tagged type and the Unscoped constraint on scoped.

Installation

libraryDependencies += "dev.zio" %% "zio-blocks-scope" % "0.0.56"

The Problem

Resource management in Scala is error-prone:

// Classic try/finally - verbose and easy to get wrong
val db = openDatabase()
try {
val tx = db.beginTransaction()
try {
doWork(tx)
tx.commit()
} finally tx.close() // What if commit() throws?
} finally db.close()
// Using - better, but doesn't prevent returning resources
Using(openDatabase()) { db =>
db // Oops! Returned the resource - use after close!
}

The Solution

Scope makes resource leaks a compile error, not a runtime bug:

import zio.blocks.scope.*
Scope.global.scoped { scope =>
import scope.*
val db: $[Database] = allocate(Resource(openDatabase()))
// Methods are hidden - can't call db.query() directly
// Must use $ to access:
val result: String = $(db)(_.query("SELECT 1"))
// Trying to return `db` would be a compile error!
result // Only pure data (String) escapes
}
// db.close() called automatically

Async

A lightweight, zero-dependency asynchronous effect type. A ready Async[A] is an A, so synchronous code composed with map / flatMap allocates nothing on the happy path while still suspending on genuinely asynchronous work.

Installation

libraryDependencies += "dev.zio" %% "zio-blocks-async" % "0.0.56"

The Problem

Asynchronous Scala forces a choice between two costs. Future allocates for every combinator and needs an ExecutionContext threaded everywhere, even when the value is already available. Full effect systems avoid that but ask you to adopt a runtime, a set of type classes, and a programming model across your whole codebase—a heavy price for a library that only occasionally suspends.

The Solution

Async[A] is a value, not a wrapper. When the result is already known, the representation is the result, so composing ready values costs nothing:

import zio.blocks.async._
// Constructors collapse to bare values; transformers inline with no allocation
val computed: Int =
Async.succeed(20).map(_ + 1).flatMap(n => Async.succeed(n * 2)).block

SQL

A thin, type-safe JDBC wrapper that maps Scala case classes to database tables using the same Schema you use for JSON and Avro codecs. No ORM runtime, no code generation — just composable SQL fragments, a derived repository abstraction, and a direct ZIO integration.

Installation

libraryDependencies += "dev.zio" %% "zio-blocks-sql" % "0.0.56"
// Optional ZIO integration
libraryDependencies += "dev.zio" %% "zio-blocks-sql-zio" % "0.0.56"

The Problem

JDBC is powerful but tedious: manual ResultSet traversal, index-based parameter binding, and repetitive CRUD boilerplate make even simple database access error-prone. ORMs solve the boilerplate but add heavy runtimes, hidden queries, and opaque magic.

The Solution

ZIO Blocks SQL derives everything from a single Schema[A]:

case class User(id: Long, name: String, email: String)
object User:
given Schema[User] = Schema.derived
// Derive the table, codec, and repository in one line
val repo = Repo.derived[User, Long]
// Use the sql"..." interpolator for custom queries
val frag = sql"SELECT * FROM user WHERE email = ${"alice@example.com"}"
  • SQL reference — DbCodec, Frag, Table, Repo, Transactor, dialects, and DDL generation
  • Query DSL guide — a four-part series building a type-safe query language on reified optics

03   Block Catalog

Take Only What You Need

Each block is a separate artifact under dev.zio. Copy the artifact name, add it to your build, and use it.

Meta Programming

Codecs

JSON support is built into zio-blocks-schema; the modules below add further formats.

Resource Management

  • Scope

    Compile-time safe resource boundaries that keep values from escaping their lifetime

    zio-blocks-scope

    JVM · JS / Scala 2.13 · 3.x

    Learn More about Scope

Dependency Injection

Configuration

Web & HTTP

Data Types

  • Chunk

    High-performance immutable indexed sequences with zero-boxing builders

    zio-blocks-chunk

    JVM · JS / Scala 2.13 · 3.x

    Learn More about Chunk
  • Maybe

    Optional values that store a present reference as is, without a wrapper object (Scala 3)

    zio-blocks-maybe

    JVM · JS / Scala 2.13 · 3.x

    Learn More about Maybe
  • Combinators

    Compile-time composition and decomposition of tuples, eithers, and unions

    zio-blocks-combinators

    JVM · JS / Scala 2.13 · 3.x

    Learn More about Combinators

Concurrency

Streaming

  • Streams

    Pull-based streaming with typed errors, zero boxing, and synchronous or asynchronous execution

    zio-blocks-streams

    JVM · JS / Scala 2.13 · 3.x

    Learn More about Streams

Telemetry

Persistence

Tooling & Codegen

04   Users

Who Is Using ZIO Blocks?

Organizations and projects that run ZIO Blocks in production.

Are you using ZIO Blocks? Let us know and join the list!