vuk, a render graph abstraction over Vulkan
vuk - A rendergraph-based abstraction for Vulkan
At a glance
- What is it?
- vuk is a C++ library that puts a render graph between your code and Vulkan, deducing render passes, image layouts, pipeline layouts and descriptor sets from how you describe the frame. It removes a large amount of Vulkan bookkeeping, at the cost of learning a rendering abstraction that is not Vulkan itself.
- Who is it for?
- vuk suits a graphics programmer who is comfortable with Vulkan's concepts but does not want to hand-maintain render passes, image layouts and descriptor set layouts for every pipeline. It does not suit a team that wants to keep full control of the Vulkan API surface, and it does not suit someone who has not written Vulkan before, since the abstractions assume knowledge of what is being abstracted.
- Can I use it commercially?
- Yes. MIT 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 83 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A render graph in front of the Vulkan API
vuk is described as a rendergraph-based abstraction for Vulkan, and it is a C++ library that sits between your renderer and the Vulkan API. The README is a feature checklist, and reading it is the fastest way to understand the scope.
The core claim is that vuk automatically deduces render passes, subpasses and framebuffers, with all the synchronization handled for you, including buffers, images and render targets, and for multiple queues. The one unchecked box in that group is fine grained synchronization using events when possible.
It also automatically transitions images into proper layouts, both for render passes and for commands outside of render passes such as blitting. That single feature removes what is usually the largest source of Vulkan bugs, the barrier that has to be inserted at exactly the right point between two uses of the same image.
The rest of the list covers pipeline creation, resource binding, allocation and debugging. Pipeline creation is automated with optional runtime shader compilation using shaderc, along with pipeline layouts and descriptor set layouts, by reflecting your shaders and deducing parameters based on the render pass and framebuffer. Resource binding is automated with hashmaps, reducing descriptor set allocations and updates. There is handling for temporary allocations for a frame and for long-term allocations with RAII handles.
Then there is the sugar, described as coming with lots of it while still exposing the full Vulkan interface: matching viewport and scissor dimensions to attachment sizes, simplified vertex format specification, blend presets, directly writable mapped uniform buffers, and automatic management of multisampling. Debugging is helped by naming the internal resources, and there is dear imgui integration code.
The audience is a graphics programmer who already knows Vulkan. That last point is the key constraint on the whole project, and the rest of this article assumes it.
The five-step frame loop
The overview section gives the shape of a vuk application, and it is short enough to be the mental model for the whole library.
First, initialize your windows and the Vulkan device. Then create a `vuk::Runtime` object. Then, each frame, you prepare a high level description of your rendering in the form of a `vuk::Pass`, bind concrete resources as inputs and outputs, bind managed resources, which are the temporary resources the render graph uses, record the execution of your render graph into a command buffer, and finally submit and present.
The order of those steps is the whole idea. In raw Vulkan you would, in effect, do the same five things, but you would do them by hand and in a much more prescriptive order: create the render pass objects, create the framebuffers, create the pipeline layouts, create the descriptor set layouts, allocate descriptors, record the command buffer with explicit barriers, and only then submit. The barriers and the layouts have to be correct at the moment you record, which is why the pipeline is often written as a sequence of passes that must be manually synchronised.
In vuk, the pass description is declarative. The graph knows which resource is written by which pass and read by which, and it computes the transitions, the render pass boundaries, the subpass merges and the barriers from that. The synchronization is a consequence of the description rather than something you write.
That is why the library is called an abstraction rather than a helper library. It is not a set of utilities around Vulkan, it is a different way of expressing the same work, and the cost of that is that you now think in passes and a graph rather than in command buffers and barriers.
The by-product is that several Vulkan features stop being your problem. The pipeline cache, the render pass compatibility, the descriptor set churn across frames: all of it becomes a graph query.
Building the examples and the three shader front ends
The quick start tells you to grab the repository, compile the examples, and run the example browser to get a feel for the library. The commands are explicit about the submodules, because the third-party dependencies come in as git submodules.
git clone http://github.com/martty/vuk
cd vuk
git submodule init
git submodule update --recursive
mkdir build
cd build
mkdir debug
cd debug
cmake ../.. -G Ninja -DVUK_BUILD_EXAMPLES=ON -DVUK_USE_DXC=OFF
cmake --build .
./vuk_all_examplesTwo details in that sequence are worth noting. The `git submodule update --recursive` is not optional, and the `ext/` directory in the repository tree is where those dependencies land. The `-DVUK_USE_DXC=OFF` flag selects the shader compilation path, and the flag name tells you there is more than one.
The examples directory confirms it. There is a `01_triangle.cpp`, a `01_triangle_dxc.cpp` and a `01_triangle_slang.cpp`, alongside `01_triangle_vcc.cpp`, so the same triangle is written four times against four different shader front ends: the shaderc path, DirectX Shader Compiler, Slang, and the VCC, the Visual Studio shader compiler, path.
That is a significant design commitment rather than a detail. vuk does not require you to adopt a particular shading language. The pipeline automation works by reflecting your shaders, and the reflection step is what tells the library how to build the pipeline layouts and the descriptor set layouts, so the front end that produces the reflection data is part of the contract rather than an implementation detail. The build flag in the quick start is how you pick one, and the DXC and Slang examples are how you see the difference.
The rest of the examples are a tour of what the graph can express. There is `02_cube.cpp`, `03_multipass.cpp`, `04_texture.cpp`, `05_deferred.cpp`, `06_msaa.cpp`, `07_commands.cpp`, `08_pipelined_compute.cpp`, `09_persistent_descriptorset.cpp` with a synchronous variant, `10_baby_renderer.cpp`, `11_composition.cpp`, `12_rt_pipeline.cpp`, `13_tessellation.cpp` and `14_mesh_shader_with_task.cpp`.
Reading them in order tells you the library's range better than any description. Deferred rendering in one file, a compute pipeline overlapped with graphics in another, a persistent descriptor set in another, and mesh shaders with task shaders in the last, which is the newest thing Vulkan has and the hardest thing to express in a graph.
What the abstraction does not hide, and the one thing it does not do
The feature list ends with a line that deserves more attention than it gets: comes with lots of sugar to simplify common operations, but still exposing the full Vulkan interface.
That is a deliberate constraint, and it is the difference between vuk and a fully managed API. When the graph cannot express something you need, you drop down to the raw Vulkan call rather than being told it is impossible. For a library that sits in front of an API with that much surface area, that escape hatch is what keeps it usable in a real renderer.
The unchecked box is fine grained synchronization using events when possible. Everything else in the synchronization group is done for you, and the events case is the one place where the automatic scheme does not apply. Synchronization events are the modern Vulkan answer to fine grained dependencies, and a graph that deduces barriers rather than events will produce correct code but not optimal code on a timeline-heavy workload. The wording in the README, when possible, suggests the author knows the automatic path is a general solution rather than the best one in every case.
There is a second limitation visible in the design rather than the list. The graph has to know what resources exist and who touches them, and that knowledge comes from the pass description you write. If your description is wrong, the graph will faithfully produce a wrong answer, and the failure will appear as a validation error or, worse, as a synchronisation bug on a different driver.
And a third, more mundane one. The feature list says the library helps debugging by naming the internal resources, which is a nice touch, but the debuggers people reach for when a GPU hang occurs are external tools, and they are the ones that will tell you the truth about what the driver did.
The realistic assessment is that vuk removes the part of Vulkan that is tedious and error-prone, which is the barrier and layout bookkeeping, and leaves the part that is genuinely interesting, which is deciding what the frame should contain.
The repository layout, the benchmarks and the release situation
The top-level entries show a conventional C++ project with a few signals worth reading. There is `include/` and `src/`, `tests/`, `examples/`, `benchmarks/`, `docs/`, `cmake/`, `ext/` for the submodules, and `bin/`. The `.clang-format` file and the `.readthedocs.yaml` alongside a `docs/` directory say that formatting is enforced and the documentation is built with Sphinx.
The presence of a `benchmarks/` directory is a good sign for a library whose entire claim is that it does less work at runtime than hand-written Vulkan. If the abstraction costs a lot of time in the graph construction phase, that is visible in a benchmark. A separate `bin/` directory is more unusual and suggests command line tools that ship alongside the library.
The release situation is the thing an adopter should note. The only recorded release is v0.5 from 2023-08-13, and the last push to the repository was on 2026-08-01. So this is a project at version 0.5 whose master branch has moved on since that tag, and whose last commit is a couple of months before the present. The README carries a documentation badge for the hosted docs and a CI badge, so the continuous integration runs on every push.
That combination, a 0.x version and a branch that is ahead of the last tag, tells you the project is a serious piece of work that has not yet committed to an API. The documentation is hosted at vuk.readthedocs.io and the project has a Discord server, so there is a community around it.
The licence is MIT, with a LICENSE file at the top of the repository.
The practical advice for anyone evaluating this is to read the current master rather than the 0.5 tag, because the tag is three years old and the interesting part of the library is the render graph implementation, which is exactly the kind of thing that changes between versions. Pin to a commit rather than to the tag if you depend on it.
Editorial conclusion
vuk suits a graphics programmer who is comfortable with Vulkan's concepts but does not want to hand-maintain render passes, image layouts and descriptor set layouts for every pipeline. It does not suit a team that wants to keep full control of the Vulkan API surface, and it does not suit someone who has not written Vulkan before, since the abstractions assume knowledge of what is being abstracted. Verify first that the version you take still supports the Vulkan features your renderer needs, that the shader compilation path you want, shaderc, DXC or Slang, is the one you build, and that the one unchecked item in the feature list, fine grained synchronization, is not something your design depends on.
Frequently asked questions
What is vuk?
It is a C++ library that provides a rendergraph-based abstraction for Vulkan. You describe each frame as a set of passes and it deduces the render passes, subpasses, framebuffers, image layout transitions, pipeline layouts and descriptor set layouts, handling the synchronization for you.
How do I build the vuk examples?
Clone the repository, run git submodule init and git submodule update --recursive, create a build directory, then configure with cmake using the Ninja generator and -DVUK_BUILD_EXAMPLES=ON, build with cmake --build . and run the ./vuk_all_examples binary.
Which shader compilers does vuk support?
Several. The examples directory contains 01_triangle.cpp, 01_triangle_dxc.cpp, 01_triangle_slang.cpp and 01_triangle_vcc.cpp, the same triangle written against four different shader front ends, and the build takes a flag such as -DVUK_USE_DXC=OFF to select the path. The pipeline automation relies on reflecting your shaders.
Does vuk hide the Vulkan API completely?
No. The feature list says it comes with lots of sugar to simplify common operations but still exposes the full Vulkan interface, so when the graph cannot express something you can drop down to the raw API call. The one capability not provided automatically is fine grained synchronization using events when possible.
How current is vuk?
The only recorded release is v0.5 from 2023-08-13, while the last push to the repository was on 2026-08-01, so the master branch is well ahead of the last tag. The project is licensed MIT and its documentation is hosted on readthedocs.
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/martty-vuk)Was this useful?