CLI tool
KhronosGroup/MoltenVK avatar
KhronosGroup/MoltenVK

MoltenVK: running Vulkan 1.4 on Metal, and where the portability subset bites

MoltenVK is a Vulkan Portability implementation. It layers a subset of the high-performance, industry-standard Vulkan graphics and compute API over Apple's Metal graphics framework, enabling Vulkan applications to run on macOS, iOS and tvOS.

5,848 stars574 forksObjective-C++Apache-2.0

At a glance

What is it?
MoltenVK layers an almost-complete subset of Vulkan 1.4 over Apple's Metal framework so the same rendering and compute code can run on macOS, iOS, tvOS and visionOS. The translation is automatic, but the subset is the part that decides whether your engine ports without changes.
Who is it for?
Adopt MoltenVK if you already ship a Vulkan renderer and want it running on Apple platforms without writing a second Metal backend, and use the Vulkan SDK build on macOS rather than assembling one yourself. Do not adopt it if your renderer depends on Vulkan features outside the portability subset, or if you are starting fresh on Apple hardware with no Vulkan code to reuse, because a native Metal backend gives you the full feature set instead of a translated subset.
Can I use it commercially?
Yes. Apache-2.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 1 day ago.
What is it written in?
Mainly Objective-C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap MoltenVK fills between Vulkan code and Apple GPUs

Apple platforms do not expose Vulkan. They expose Metal, and Metal has its own shading language and its own API surface. A studio with a Vulkan renderer therefore faces a choice: maintain a second backend written in Metal, or find a translation layer. MoltenVK is that translation layer. The README describes it as a layered implementation of Vulkan 1.4 graphics and compute functionality built on Apple's Metal framework, targeting macOS, iOS, tvOS, visionOS, Simulators and Mac Catalyst, across all Apple architectures including Apple Silicon. The intended audience is not someone writing a first renderer for a Mac. It is someone who already has Vulkan code, often a game engine, and wants it running on Apple hardware without a fork of the rendering layer. The README is explicit that MoltenVK uses only Apple's publicly available APIs and no private or undocumented calls, which matters because it means an app built on it stays eligible for standard distribution channels including the App Store.

How the SPIR-V to MSL conversion actually flows

The mechanism is two-stage. At the shader level, Vulkan consumes SPIR-V while Metal consumes the Metal Shading Language, so MoltenVK converts SPIR-V shaders into their MSL equivalents automatically. That converter is not only a runtime component: it also ships as a stand-alone command-line macOS tool called MoltenVKShaderConverter, which lets you convert shaders at development time rather than at load time. At the API level, MoltenVK presents Vulkan entry points and maps them onto Metal calls. The README calls the result an almost-complete subset of Vulkan 1.4, and that word subset is doing real work. This is not a full Vulkan implementation with every extension present. It is a portability implementation, and the shape of what is available is described by the VK_KHR_portability_subset extension. One consequence shows up immediately in device enumeration. Because MoltenVK supports that extension, when the Vulkan Loader from the Vulkan SDK runs MoltenVK on macOS, the loader will only include MoltenVK VkPhysicalDevices in the list returned by vkEnumeratePhysicalDevices() if the VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR flag is enabled in vkCreateInstance(). If your instance creation does not set that flag, the device simply will not appear, and the failure looks like a missing GPU rather than a missing flag.

Installing MoltenVK: the SDK path and the source build path

The README gives two routes and recommends one. For macOS development it says the recommended method is the Vulkan SDK from LunarG, which already includes a MoltenVK runtime library for macOS. That path also brings the Validation Layers, which the README calls an essential debugging tool because they identify inappropriate use of the Vulkan API. If you are on iOS, tvOS or visionOS, or you want a different build than the one in the macOS SDK, the README points to pre-built MoltenVK binary libraries attached to repository commits in the GitHub Actions list. A custom build starts by fetching the source and its external dependencies. The README states you need cmake and python3, with ninja optional for faster dependency builds:

bash
brew install cmake
brew install python3
brew install ninja

Then clone the repository and run the fetchDependencies script from inside it:

bash
git clone https://github.com/KhronosGroup/MoltenVK.git
cd MoltenVK
./fetchDependencies [platform...]

The platform argument is not optional. The README lists the accepted choices as --all, --macos, --ios, --iossim, --maccat, --tvos, --tvossim, and you can pass several at once. The result is one XCFramework per external dependency, each containing binaries for the platforms you asked for. Building the package itself is driven by the top-level Makefile, which wraps xcodebuild against MoltenVKPackaging.xcodeproj and the MoltenVK Package scheme. The default all target builds macos, ios, iossim, tvos, tvossim, visionos and visionossim in sequence, with the maccat target commented out in the Makefile because of unresolved build issues on Mac Catalyst; the visionOS targets carry a comment that they require Xcode 15 or later. A single-platform build is just the target name:

bash
make macos

That invokes xcodebuild with the macOS-only scheme and a generic/platform=macOS destination. If xcpretty is on your PATH the Makefile pipes output through it and keeps a full log in xcodebuild.log; otherwise it falls back to xcodebuild -quiet.

The portability subset is the real limitation

The phrase almost-complete subset is the honest core of this project, and it is where ports fail. Vulkan extensions that Metal has no equivalent for cannot be emulated into existence, so code paths that depend on them need a fallback or a removal. The README does not enumerate which extensions are absent in the text available here; it defers that to the compliance discussion and to Docs/MoltenVK_Runtime_UserGuide.md. That is the first thing to check before committing to a port, because a renderer that leans on a feature outside the subset will not fail at build time. It will fail at runtime, on device, often as a validation error or a silently wrong image. The second limitation is structural rather than feature-based: MoltenVK is a translation layer, so every Vulkan call passes through mapping logic before reaching Metal. That is the price of not writing a Metal backend, and it is the reason the moltenvk vs metal performance question keeps coming up. The README does not publish performance figures, and the repository does not present one. A third limitation is platform reach. The README names macOS, iOS, tvOS, visionOS, Simulators and Mac Catalyst, and notes that maccat is excluded from the default build because of unresolved build issues. If Mac Catalyst is your target, you are on a path the project itself has not finished.

When a native Metal backend is the better answer

The real alternative is not another portability layer. It is Metal itself, and the difference is one of approach rather than degree. MoltenVK accepts Vulkan API calls and translates them, converting SPIR-V to MSL along the way, which preserves your existing renderer and its shader pipeline. A Metal backend does the opposite: you rewrite the rendering layer against Metal directly, in MSL, with no translation step, and in exchange you get the full Metal feature set rather than the portability subset. The trade is code reuse against feature ceiling. If your engine already has a Vulkan backend and a Metal backend is a large, permanent maintenance burden, MoltenVK is the cheaper path. If the target is Apple platforms only, and no Vulkan code exists yet, writing Metal directly avoids a translation layer you would be paying for on every frame. There is a middle case worth naming: a project that ships Vulkan everywhere and treats Apple as one more platform will find the subset boundary more tolerable than a project whose most demanding rendering features are exactly the ones Metal exposes and Vulkan-over-Metal does not.

Maintenance, licensing and the upgrade path

MoltenVK is not archived, and the last push to the main branch was on 2026-09-21, one day before this writing, so the repository is receiving changes. Recent releases are v1.4.2 on 2026-07-24, preceded by v1.4.2-rc1 on 2026-07-19 and v1.4.1-rc1 on 2025-11-25. The release cadence visible here is a release candidate followed by a final release within days, which suggests the project tags a candidate before promoting it. The licence is Apache-2.0, which is permissive and includes an explicit patent grant; that is a different posture from a copyleft licence, and it is generally the easier one to satisfy in a closed-source shipping product. This is not legal advice, and the obligations that actually bind you depend on how you distribute the binary and what notices you carry. On upgrade cost, the source-build route means re-running fetchDependencies whenever external dependency revisions change, since those revisions live in the ExternalRevisions directory and the script turns them into XCFrameworks. If you took the Vulkan SDK route on macOS, the MoltenVK version you get is the one bundled with the SDK, so upgrading means upgrading the SDK. The README also documents a path for installing MoltenVK to replace the libMoltenVK.dylib inside the Vulkan SDK, which is the option for pinning a build the SDK does not ship. The README does not document rollback for any of these paths.

Editorial conclusion

Adopt MoltenVK if you already ship a Vulkan renderer and want it running on Apple platforms without writing a second Metal backend, and use the Vulkan SDK build on macOS rather than assembling one yourself. Do not adopt it if your renderer depends on Vulkan features outside the portability subset, or if you are starting fresh on Apple hardware with no Vulkan code to reuse, because a native Metal backend gives you the full feature set instead of a translated subset. Before committing, verify three things in the Docs directory: whether your required extensions are listed as supported, whether your SPIR-V shaders survive the automatic conversion to MSL, and whether your instance creation enables VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR, without which the loader will not return the MoltenVK physical device at all.

Frequently asked questions

How does MoltenVK work?

It is a layered implementation of Vulkan 1.4 graphics and compute functionality built on Apple's Metal framework. It maps Vulkan API calls onto Metal and automatically converts SPIR-V shaders into their Metal Shading Language equivalents.

How do I install MoltenVK on macOS?

The README recommends the Vulkan SDK from LunarG, which already includes a MoltenVK runtime library for macOS. For a custom build you clone the repository and run ./fetchDependencies with one or more platform flags, then build the package through the Makefile.

What is MoltenVK compared to Vulkan?

Vulkan is the API specification. MoltenVK is a portability implementation of an almost-complete subset of Vulkan 1.4 that runs on top of Metal, so it is the piece that lets Vulkan code execute on macOS, iOS, tvOS and visionOS.

Is MoltenVK free to use?

The repository is licensed under Apache-2.0, a permissive licence that permits commercial and closed-source use subject to its notice requirements. What those requirements mean for your distribution is a question for your own counsel.

Why does vkEnumeratePhysicalDevices() not return a device with MoltenVK on macOS?

Because MoltenVK supports VK_KHR_portability_subset, the Vulkan Loader only includes MoltenVK VkPhysicalDevices when the VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR flag is enabled in vkCreateInstance(). Without that flag the device is omitted from the list.

Can MoltenVK convert shaders ahead of time instead of at runtime?

Yes. The SPIR-V converter is packaged as a stand-alone command-line macOS tool called MoltenVKShaderConverter, so shaders can be converted at development time. The same converter is embedded in the runtime for automatic conversion.

Official sources

  1. Issues
  2. KhronosGroup/MoltenVK on GitHub
  3. License: Apache-2.0
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/khronosgroup-moltenvk.svg)](https://hysenlabs.com/projects/khronosgroup-moltenvk)