ArceOS: a modular Rust unikernel for OS experiments
An experimental modular OS written in Rust.
At a glance
- What is it?
- ArceOS is an experimental modular operating system, or unikernel, written in Rust, where the kernel is assembled from separately configurable modules rather than one monolith. It runs on four architectures under QEMU and is a good teaching and prototyping base, but Linux application compatibility, interrupt-driven I/O and async I/O are still unchecked boxes.
- Who is it for?
- Adopt ArceOS if you are teaching operating systems, prototyping a unikernel, or want a Rust kernel whose modules you can switch on one at a time instead of forking a monolithic tree. Do not adopt it to run Linux binaries, because compatibility with Linux applications is still an open item on the project list, and treat the file system and network stack as a teaching implementation rather than a production one.
- 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 146 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A kernel whose parts are chosen at build time
ArceOS describes itself as an experimental modular operating system, or unikernel, written in Rust, and the README marks it clearly as work in progress. It was inspired a lot by Unikraft.
The word modular is doing real work in that description. Rather than one kernel binary that contains everything, ArceOS is a Cargo workspace of separate crates, and the Makefile exposes a FEATURES variable that turns individual modules on. The available feature names visible in the README examples include alloc, paging, net, page-alloc-4g, driver-bcm2835-sdhci, driver-ixgbe and driver-ramdisk. A kernel for a Raspberry Pi with an SD card driver is assembled differently from a bare-metal x86_64 kernel with an ixgbe NIC and a ramdisk.
That approach has an obvious appeal for anyone learning kernel structure, since you can read one module and understand one subsystem without reverse engineering the whole tree. It also has a cost: the number of combinations multiplies, and the platform and driver configuration becomes part of the interface you must learn.
For a production operating system the project is candid about where it stands. The features list marks compatible with Linux apps, interrupt driven device I/O and async I/O as unchecked, while architecture support, platform support, multi-threading, the schedulers, VirtIO drivers, the TCP and UDP stack, synchronisation, SMP scheduling with per-cpu run queue and the file system are all marked done.
How modules, api and ulib divide the work
The workspace manifest makes the architecture readable. Members are grouped into three families: modules, api and ulib.
The modules directory holds the kernel internals: axalloc, axconfig, axdisplay, axdriver, axfs, axhal, axlog, axmm, axnet, axns, axruntime, axsync, axtask, axdma and axipi. The names map onto familiar kernel subsystems, from the allocator and the memory manager through the task scheduler and the networking stack, with axdma and axipi standing out as the kind of low-level interface modules that a unikernel for embedded or accelerator hardware would need.
The api directory is the boundary between the kernel and applications: axfeat for feature description, arceos_api for the native ArceOS application interface and arceos_posix_api for a POSIX-shaped surface.
The ulib directory holds the user-facing libraries, axstd and axlibc. axstd is the crate an application depends on in practice, and it is designed to feel like the Rust standard library: the README instructs you to call axstd functions just like the Rust std library. axlibc sits alongside it for C compatibility.
The separation is the point of the design. Applications link against a library interface, and the kernel underneath is assembled from modules selected by feature flags. This is also why the project can offer a C path: a C application is compiled into objects with musl and linked against the same platform.
Running the hello world through the Docker image
The README offers two routes. The first is the container, and it is the shortest path to a running kernel because the image already carries the toolchain, the cross compilers and QEMU.
Build the image from the Dockerfile at the repository root:
docker build -t arceos -f Dockerfile .That Dockerfile is more than a convenience wrapper. It starts from rust:slim, installs the LLVM and build tooling, installs cargo-binutils, axconfig-gen and cargo-axplat through cargo install, downloads the musl cross toolchains for aarch64, riscv64, x86_64 and loongarch64, and builds QEMU 9.2.4 from source with softmmu targets for all four architectures and slirp enabled for user-mode networking.
With the image built, you start a container with the source tree mounted and the working directory set:
docker run -it -v $(pwd):/arceos -w /arceos arceos bashInside that container the actual build and run is a single make invocation:
make A=examples/helloworld ARCH=aarch64 runThe ARCH value must be one of riscv64, aarch64, x86_64 or loongarch64. The Makefile also accepts LOG, with levels from off to trace, MODE for release or debug, SMP to override the CPU count, and the runtime switches BLK, NET, GRAPHIC, BUS, MEM, DISK_IMG, ACCEL, QEMU_LOG, NET_DUMP, NET_DEV and VFIO_PCI.
Building without Docker and the musl toolchain requirement
The manual route needs three Rust tools installed with cargo, which the README specifies precisely:
cargo install cargo-binutils axconfig-gen cargo-axplatcargo-binutils provides the rust-objcopy and rust-objdump tools, axconfig-gen handles kernel configuration and cargo-axplat handles platform configuration. On top of that you need QEMU, installed with the apt package on Debian and Ubuntu or with brew on macOS, and, if you want to build C applications, libclang-dev.
The C path additionally requires musl cross toolchains, downloaded and unpacked for each architecture:
wget https://musl.cc/aarch64-linux-musl-cross.tgz
tar zxf aarch64-linux-musl-cross.tgzThe full list in the README covers aarch64, riscv64, x86_64 and a loongarch64 gcc 13.2.0 build hosted on GitHub, and then puts every toolchain bin directory on the PATH in one export line.
The build command itself mirrors the container one, with the application path and architecture supplied as variables:
make A=path/to/app ARCH=<arch> LOG=<log>One subtlety worth flagging: the README states that the runtime arguments such as BLK and GRAPHIC only take effect at runtime, not at build time. A kernel built without those flags still boots, but the corresponding devices are absent when QEMU starts.
Running the httpserver and the NET flag that decides connectivity
The worked example in the README runs the HTTP server example on qemu-system-aarch64 with four cores and log level info:
make A=examples/httpserver ARCH=aarch64 LOG=info SMP=4 run NET=yThe NET=y argument is the part to remember. The README states plainly that it is required to enable the network device in QEMU, and without it the kernel starts with no virtio-net device attached.
The example tree gives a decent picture of what the kernel can do today. There are Rust examples for helloworld, httpclient, httpserver and shell, plus helloworld-c, httpclient-c and httpserver-c variants, and a helloworld-myplat example that shows the custom platform path. The shell example is the most revealing of the set, because a shell implies a usable file system and console device, and the presence of the httpclient example implies a working TCP client on top of the smoltcp-based network stack.
Examples can live outside the source tree as well. The README describes the app-helloworld and arceos-apps repositories as places where out-of-tree applications are written, and the applications in the examples directory serve as the reference. For Rust applications the steps are: create a package with no_std and no_main, add axstd as a dependency, mark the main function with #[unsafe(no_mangle)], and build with the same make invocation from the application directory.
Targeting real boards through MYPLAT, FEATURES and BUS
QEMU is the default target, but the project supports specific platforms and devices, and the mechanism is a manual link step plus three Makefile variables.
The application has to name the platform package it wants, by adding an extern crate declaration for the target crate:
extern crate axplat_aarch64_raspi;Then the build selects that platform and the drivers it needs:
make MYPLAT=axplat-aarch64-raspi SMP=4 A=examples/shell FEATURES=page-alloc-4g,driver-bcm2835-sdhci BUS=mmioThe example builds the shell app for the Raspberry Pi 4 with the SD card driver, allocating pages with the 4g allocator and using the memory-mapped I/O bus. A second example covers the bare-metal x86_64 platform, where the application path and the platform configuration file are both given, and the ixgbe network driver and ramdisk driver are selected:
make PLAT_CONFIG=$(pwd)/configs/custom/x86_64-pc-oslab.toml A=examples/httpserver FEATURES=page-alloc-4g,driver-ixgbe,driver-ramdisk SMP=4The Makefile documents the wider variable set, including MYPLAT as the package name of the target platform crate, PLAT_CONFIG as the path to a platform configuration file, BUS with the choices mmio or pci, MEM with a 128M default, and UIMAGE for generating a U-Boot image. The configs directory holds the platform configuration files these variables point at.
Licensing, versions and the shape of the tree
The workspace metadata gives version 0.2.0, edition 2024, and a license expression of GPL-3.0-or-later OR Apache-2.0 OR MulanPSL-2.0. The repository root carries the matching licence files, LICENSE.Apache2, LICENSE.GPLv3, LICENSE.MulanPSL2 and LICENSE.MulanPubL2. In practice that triple choice means you can take the code under whichever of those terms suits your distribution, though you should read the files yourself rather than relying on the summary.
One release has been published, v0.2.0 on 2025-07-13, and it matches the version in the workspace manifest. The repository is not archived, and the last push was on 2026-06-01. The README carries a work in progress marker.
Beyond the workspace there is a supporting structure: a Makefile at the root, a Dockerfile, a scripts directory, a tools directory, a doc directory, a rust-toolchain.toml that pins the Rust version used by the build, and an api directory that holds the shared interfaces. The axstd crate is the dependency most applications declare, and the README points to axstd documentation for using the library functions the way you would use Rust std.
Editorial conclusion
Adopt ArceOS if you are teaching operating systems, prototyping a unikernel, or want a Rust kernel whose modules you can switch on one at a time instead of forking a monolithic tree. Do not adopt it to run Linux binaries, because compatibility with Linux applications is still an open item on the project list, and treat the file system and network stack as a teaching implementation rather than a production one. Before your first build, confirm you have cargo-binutils, axconfig-gen and cargo-axplat installed, keep the musl cross toolchains on your PATH, and expect to pin the tree to the v0.2.0 release from 2025-07-13 because the branch itself has only been pushed to on 2026-06-01.
Frequently asked questions
What is ArceOS and is it a full Linux-compatible operating system?
ArceOS is an experimental modular operating system, or unikernel, written in Rust, inspired by Unikraft. Compatibility with Linux applications is still an unchecked item on the project's own feature list.
How do I build and run ArceOS on my machine?
The shortest path is the container: docker build -t arceos -f Dockerfile ., then docker run -it -v $(pwd):/arceos -w /arceos arceos bash, and inside it make A=examples/helloworld ARCH=aarch64 run. For a manual build you install cargo-binutils, axconfig-gen and cargo-axplat plus QEMU, then run make A=path/to/app ARCH=<arch>.
Which architectures and platforms does ArceOS support?
The supported architectures are x86_64, riscv64, aarch64 and loongarch64, with QEMU pc-q35 for x86_64 and virt for the others. Beyond those defaults you can target specific boards by linking the platform crate and setting MYPLAT, for example axplat-aarch64-raspi for Raspberry Pi 4.
Why does my ArceOS network example not connect?
The README states that the NET=y argument is required to enable the network device in QEMU. The runtime arguments such as NET and BLK take effect at run time rather than build time, so a kernel started without them boots with the corresponding devices absent.
Can I write applications in C for ArceOS?
Yes. A C application needs an axbuild.mk listing the objects to build and a features.txt listing the features to enable, and it is compiled with musl cross toolchains. The examples directory includes helloworld-c, httpclient-c and httpserver-c as references.
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/arceos-org-arceos)Was this useful?