stlab brings futures and channels to C++ without the standard library future baggage
ASL libraries will be migrated here in the stlab namespace, new libraries will be created here.
At a glance
- What is it?
- STLab is a C++17 and later library set providing futures, channels and await helpers, split across two packages after the execution layer was carved out into stlab-execution. It suits teams that want actor style concurrency with deterministic control over the executor, and it asks for CMake 3.24 plus a rebuild of every consumer.
- Who is it for?
- STLab fits C++ teams that want futures and channels with an executor they can pin, port, or replace, and that value a library that names its own concurrency contracts rather than leaning on std::async. It does not fit codebases pinned to the old stlab-core target names without accepting the rebuild that the package split forces, and it is the wrong tool when a single-threaded async runtime would do.
- Can I use it commercially?
- Yes. BSL-1.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 9 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the concurrency library is meant to replace
STLab's concurrency library exists to fix specific problems, and the README names them: it provides futures and channels as high-level abstractions for implementing algorithms that ease the use of multiple CPU cores while minimizing contention. The target of the critique is stated just as plainly, since the library is described as solving several problems of the C++11 and C++17 TS futures.
That is a narrower ambition than a general parallel programming framework. There is no lock abstraction, no thread pool object of your own, no work-stealing scheduler to configure. The unit of abstraction is a future you can await or an await helper that composes with one, plus channels that move values between tasks. The contention claim is about how those abstractions schedule work, not about a benchmark the project publishes. No numbers are offered anywhere in the README, so any throughput comparison you have seen attributed to this project came from somewhere else.
The library is part of a wider set under the namespace stlab, published under the Boost Software License 1.0, with headers, CMake packages, tests and API reference. The repository description also says that ASL libraries will be migrated here in the stlab namespace and that new libraries will be created here, so this repository is both a migration target and a home for work in progress.
The execution layer was split out, and the split has a cost
The most consequential structural fact is that STLab publicly depends on a separate package, stlab-execution. That package owns tasks, executors, timers, pre_exit, the existing public header paths and the compiled execution runtime. Linking stlab::stlab obtains both layers at once. Standalone execution clients link stlab::execution instead, and the legacy stlab-core and stlab::stlab-core targets are INTERFACE compatibility targets that refer to execution rather than to a second binary.
Three consequences follow. First, consumers must rebuild; existing v2 C entry points and source spellings are preserved, but the binaries are not interchangeable. Second, independence is achieved with inline namespaces, which preserve source-level names rather than the C++ ABI of previously built clients. That is a deliberate trade: source compatibility yes, ABI compatibility no. Third, ownership of configuration is split. stlab/config.hpp includes stlab/execution/config.hpp, STLab owns only its release version, namespace and coroutine configuration, and execution owns backend selection, export and common feature macros. STLab uses stlab-execution 1.0.1 and cpp-library 5.6.0, and local CPM source overrides must use :PATH cache types on Windows.
Documentation is uneven across the seam. API reference for STLab-owned APIs is published at stlab.cc, but the repository states that there is no published execution documentation site yet, so the lower-level contracts live in the execution README and in a local Doxygen build.
Consuming the libraries with CPM and CMake
The recommended consumption path is CPM, which fetches dependencies at configure time. The README gives the two lines that go into your CMakeLists.txt:
CPMAddPackage("gh:stlab/[email protected]")
target_link_libraries(app PRIVATE stlab::stlab)The version in that snippet is a placeholder, and the README says to replace 2.1.2 with the desired version from the releases page. Tagged releases are published on GitHub Releases, with v2.4.0 dated 2026-10-13 in the recent history.
Installed consumers take a different route and use find_package instead, so the same target name resolves from an installed prefix rather than from a fetched source tree:
find_package(stlab CONFIG REQUIRED)
target_link_libraries(app PRIVATE stlab::stlab)For that to work you set CMAKE_PREFIX_PATH to the prefix containing both packages, or supply an independently installed execution prefix. Installed consumers require stlab-execution 1.0.1 or later, which is the version floor to keep in mind when you write a package manager rule or a CI image definition.
Building from source with the CMake presets
STLab is a standard CMake project, and the README offers a configure invocation with the build directory placed outside the source tree. The command is:
cmake -S . -B ../BUILD -DCMAKE_BUILD_TYPE=# SEE BELOWThe build type placeholder is required unless you are using Visual Studio or another multi-config generator, where you pick Release or Debug at build time instead. Two other options matter: -DBUILD_TESTING=OFF turns off tests if you intend only to build the library, and -DCMAKE_CXX_STANDARD= selects 17, 20 or 23.
The presets route is what the README actually recommends for day to day work, and it is where the version requirements bite. Building the library requires CMake 3.24 or later, but this repository's schema-8 presets require CMake 3.28 or later, while the execution schema-5 presets still use 3.24. On Debian or Ubuntu you may need to use snap to find a CMake new enough for the presets. For MSVC you may need to invoke VCVARSALL.BAT with an appropriate option for your target architecture.
Testing and development use Ninja and doctest, fetched by CMake rather than vendored. The tested-on list is Linux with GCC 11, Linux with Clang 14, MacOS 11 with Apple-clang 13.0.0, and Windows with Visual Studio 16, and the stated requirement is a standards-compliant C++17, C++20 or C++23 compiler.
Executor and thread system choices are build-time decisions
The configuration surface is where this library differs from most C++ headers, because the concurrency backend is chosen when the project is configured rather than when a program starts. The main executor is selected with -DSTLAB_MAIN_EXECUTOR, accepting qt5, qt6, libdispatch, emscripten, portable or none. The default is platform dependent. The portable option is an STLab-owned queue serviced by stlab::main_executor_run() and is opt-in, and Windows has no process main queue, so the default there is none unless Qt is found.
Threads are configured separately. -DSTLAB_THREAD_SYSTEM accepts win32, pthread, pthread-emscripten, pthread-apple or none, and -DSTLAB_TASK_SYSTEM accepts portable, libdispatch, windows or emscripten, again with a platform-dependent default. The emscripten task system is the cooperative, threadless backend. Pool sizing comes from -DSTLAB_TASK_POOL_MAXIMUM, where a default of zero implies a pool size of std::thread::hardware_concurrency, and a non-zero value implies STLAB_TASK_SYSTEM=portable.
One escape hatch exists for compilers that do not conform: -DSTLAB_NO_STD_COROUTINES=ON suppresses the use of standard coroutines. The practical reading of all this is that the library is designed for projects that want to pin their execution model, which is also the reason the options are numerous.
Where the documentation is thin and the migration will hurt
Several gaps are worth naming plainly. The README does not show a usage example beyond the two CMake snippets, so a newcomer gets no worked example of awaiting a future or using a channel. The examples directory in the repository holds only a placeholder file, which means the examples that other projects of this kind usually carry are not there. The concurrency library is documented through a Doxygen group page, and there is no separate publication describing the channel API in prose.
Documentation generation is itself a small build system of its own. API reference uses Doxygen with doxygen-awesome-css and is built with -DBUILD_DOCS=ON or through the docs CMake preset, which is run as cmake --preset=docs followed by cmake --build --preset=docs, with output under build/docs/html, and a doxygen preset as an alias writing to build/doxygen/html. Formulas in comments use Doxygen math markup, and the HTML output enables MathJax 3 so no LaTeX toolchain is needed locally or in CI. Release changelogs live in CHANGES.md.
The upgrade path is the sharpest edge. The package split, the INTERFACE compatibility targets and the inline namespace scheme all work together, but the outcome is that a consumer who had built against the previous arrangement must rebuild and must move to stlab-execution 1.0.1 or later. Migration cost is therefore a rebuild plus a dependency floor, not a source rewrite.
How STLab compares with the standard library futures
The alternative this project positions itself against is the standard library. std::async, std::future and std::promise are what the README says the concurrency library solves problems of, and the difference in approach is one of ownership. The standard library hands you a future that may or may not have a thread behind it, and the standard says little about where the work runs, which makes it awkward for algorithms that need many small pieces of work spread across cores without contention.
STLab separates the two halves that the standard library merges. The value semantics stay on the STLab side as futures, channels, await helpers, ready futures and serial queues, and the scheduling machinery moves to the execution package with tasks, executors and timers. Once that split exists, the backend becomes a build option rather than a language feature, so a project can run the same algorithm on libdispatch on macOS, on a portable pool on Windows, or on the cooperative threadless Emscripten task system in a browser build.
The other alternative worth weighing is a structured concurrency library with its own runtime and its own executor model, where the runtime is the product rather than a swappable backend. STLab takes the opposite bet: the algorithm code is written against futures and channels, and the executor is chosen by configuration. That bet is the whole case for the library, and it is also the case to check against your own constraints on determinism and portability.
Editorial conclusion
STLab fits C++ teams that want futures and channels with an executor they can pin, port, or replace, and that value a library that names its own concurrency contracts rather than leaning on std::async. It does not fit codebases pinned to the old stlab-core target names without accepting the rebuild that the package split forces, and it is the wrong tool when a single-threaded async runtime would do. Verify first that your compiler set matches the listed matrix (GCC 11, Clang 14, Apple-clang 13.0.0, Visual Studio 16), that your CMake is 3.24 or newer (3.28 for the schema-8 presets), and that you can supply stlab-execution 1.0.1 or later alongside the stlab package you install.
Frequently asked questions
What does stlab::stlab give me over std::future and std::async?
The concurrency library provides futures and channels as abstractions for using multiple CPU cores while minimizing contention, and the README describes it as solving several problems of the C++11 and C++17 TS futures. Its distinguishing feature is that the executor is a separate layer, stlab-execution, chosen at build time.
How do I add STLab to a CMake project?
The README recommends CPM, adding CPMAddPackage("gh:stlab/[email protected]") and target_link_libraries(app PRIVATE stlab::stlab) to your CMakeLists.txt, replacing the version with the one you want. Installed consumers use find_package(stlab CONFIG REQUIRED) and the same target, with CMAKE_PREFIX_PATH pointing at the prefix containing both packages.
Which executor backend should I pick for a cross platform build?
The main executor is chosen with -DSTLAB_MAIN_EXECUTOR, whose accepted values are qt5, qt6, libdispatch, emscripten, portable and none, with a platform-dependent default. Windows has no process main queue, so the default there is none unless Qt is found, and portable is an STLab-owned queue that must be opted into.
What are the compiler and CMake requirements for STLab?
A standards-compliant C++17, C++20 or C++23 compiler is required, and the library is tested with GCC 11, Clang 14, Apple-clang 13.0.0 and Visual Studio 16. Building requires CMake 3.24 or later, while this repository's schema-8 presets require CMake 3.28 or later.
Do I have to rebuild my project after upgrading STLab?
Yes, the README states that consumers must rebuild. Existing v2 C entry points and source spellings are preserved, and the legacy stlab-core targets are INTERFACE compatibility targets referring to execution, but independent inline namespaces preserve source-level names rather than the C++ ABI of previously built clients. Installed consumers need stlab-execution 1.0.1 or later.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/stlab-stlab)Was this useful?