Skip to content

Slick 4#3542

Open
hvesalai wants to merge 17 commits intomainfrom
slick4
Open

Slick 4#3542
hvesalai wants to merge 17 commits intomainfrom
slick4

Conversation

@hvesalai
Copy link
Copy Markdown
Member

@hvesalai hvesalai commented Apr 21, 2026

Slick 4

Slick 4 is a major release that modernises the execution engine from the ground up while keeping everything users care about — the query DSL, DBIOAction combinators, profile imports, SQL generation, HikariCP integration, and code generation — completely unchanged. The core is now built on Cats Effect 3, giving Slick a rock-solid, principled concurrency foundation. Three ready-made facades cover Future with Reactive Streams, Cats Effect IO with FS2, and ZIO with ZIO Streams — all sharing the same DBIOAction API. The threading model has been rewritten so that connection use, backpressure, cancellation, and lifecycle management are all correct by construction rather than by convention.

Three facades — one API

Facade Module Effect type Stream type
slick.future.Database slick-future scala.concurrent.Future Reactive Streams DatabasePublisher[T]
slick.cats.Database slick (core) cats.effect.IO fs2.Stream[IO, T]
slick.zio.Database slick-zio zio.Task zio.stream.ZStream[Any, Throwable, T]
  • slick.future.Databasedb.run returns Future[R] and db.stream returns a Reactive Streams DatabasePublisher[T], exactly as in Slick 3. The only mechanical changes are database construction and the removal of ExecutionContext parameters from DBIO combinators.
  • slick.cats.Databasedb.run returns IO[R], db.stream returns fs2.Stream[IO, T], and lifecycle is managed with Resource[IO, Database].
  • slick.zio.Databasedb.run returns Task[R], db.stream returns ZStream[Any, Throwable, T], and lifecycle is managed with ZIO[Scope, Throwable, Database].

Execution engine

  • Cats Effect 3 core — the new Database[F[_], S[_]] trait is abstract over both the effect type and the stream type. db.run(action) returns F[R] and db.stream(action) returns S[T], where F and S are supplied by whichever facade you use. All JDBC blocking work is dispatched via F.blocking, which maps to the appropriate blocking thread pool for the chosen effect type.
  • AsyncExecutor removed — the bespoke thread-pool abstraction and its intricate minThreads == maxThreads == maxConnections constraint are gone. Connection-pool sizing is now independent of thread counts; size HikariCP to what the database server can handle and nothing more.
  • Transaction rollback on fiber cancellation — if the fiber running a .transactionally block is cancelled the transaction is rolled back automatically, with no extra user code required.
  • ExecutionContext removed from DBIOAction combinatorsmap, flatMap, filter, withFilter, cleanUp, zipWith, and DBIO.fold no longer require an implicit ExecutionContext. DBIO composition is now boilerplate-free.

Concurrency control

  • ConcurrencyControl — a new, principled two-layer execution gate replaces the old queue:
    • AdmissionControl — enforces queueSize (fail-fast when the caller queue is full) and maxInflightActions (caps the number of concurrently running DBIO chains for the full chain lifetime, not just while holding a connection).
    • ConnectionArbiter — manages connection-slot allocation with ordered fairness, prioritising chain continuations over fresh submissions to prevent head-of-line blocking.
  • Configurable timeoutsinflightAdmissionTimeout and connectionAcquireTimeout let you bound how long a caller waits for a slot, distinct from JDBC execution time.
  • db.controlStatus — returns a live snapshot of availableConnectionSlots, pendingConnectionSlots, availableAdmissionQueueSlots, and availableInflightSlots, making it straightforward to distinguish admission saturation from connection-slot contention.

Streaming Internals

  • Iterator-based streaming internals — the old push/emit architecture has been removed and the CloseableIterator model (that was at the bottom of the stack earlier) has been surfaced. The result is simpler code and correct demand-driven back-pressure throughout.
  • bufferNext overload removed — Slick 4's pull model keeps the JDBC cursor positioned on the current row until the subscriber signals new demand, so LOB handles and ResultSetMutator values are safe without any flag.
  • DatabasePublisher.close is idempotent — safe to call multiple times or from finalizers.

Database construction

  • Database.forXxx factory methods moved to DatabaseConfig.forXxxDatabaseConfig bundles the profile with the connection configuration. Each facade provides its own idiomatic lifecycle: open/use for slick.future, make/resource for slick.cats, and make/scoped for slick.zio.

Documentation

  • All documentation have been updated to reflect the new API.
  • Migration guide (migrating-to-slick4.md) — covers every breaking change, includes a mechanical checklist suitable for automated tooling, and maps every Slick 3 pattern to its Slick 4 equivalent.
  • All documentation examples updated to the new construction API.

@hvesalai hvesalai requested a review from nafg April 21, 2026 08:15
@github-actions
Copy link
Copy Markdown
Contributor

Incompatible changes

The compatibility report is too large to post as a PR comment —
this typically means a very large number of API changes relative
to the previous release.

The full report is available as a downloadable artifact from the
workflow run.

To generate it locally, run:

sbt site/buildCompatReport

The report will be written to site/target/compat-report.md.

hvesalai added 17 commits April 21, 2026 13:04
Migrate execution layer to Cats Effect 3 and FS2: replace Future-based
thread pool with CE3 blocking dispatcher, db.run() now returns F[R],
db.stream() returns Stream[F, T], transactions roll back on fiber
cancellation. Remove AsyncExecutor, ExecutionContext from DBIOAction
combinators and model-building API.
- removed reactive-stream-tests from build, the will be added back once we add Reactive Streams support back
- Add ConcurrencyControl as the unified execution control layer for database
  runs/streams.
- Implement AdmissionControl to enforce queueSize fail-fast admission and
  maxInflightActions gating for full DBIO chain lifetime.
- Implement ConnectionArbiter to manage connection-slot acquisition/release with
  ordered fairness for chain continuations and fresh submissions.
- Wire controls through BasicBackend/JdbcBackend, expose concurrency gauges, and
  update docs/tests for new config keys and overload behavior.
…emit based

The old code already had iterators around, but they were turned into push-style
emiters. The new iterator-based approach allowed for a better integration with
pull-based fs2 streams.
- removes vars and uses composition of iterators instead, making the code both
  more robust and more readable
* Prepare streaming internals for new API
@github-actions
Copy link
Copy Markdown
Contributor

Incompatible changes

The compatibility report is too large to post as a PR comment —
this typically means a very large number of API changes relative
to the previous release.

The full report is available as a downloadable artifact from the
workflow run.

To generate it locally, run:

sbt site/buildCompatReport

The report will be written to site/target/compat-report.md.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant