BLAFS debloats a container by keeping only the files a workload touched
A tool for Container Debloating that removes bloat and improves performance and security
At a glance
- What is it?
- BLAFS is a Go and C filesystem that converts a container image into a bloat-aware filesystem, records which files a profiling workload actually uses, and then produces a new image containing only those files. The gain is large on a Redis image, and the risk is that your profiling workload did not exercise every code path the production one will.
- Who is it for?
- Adopt BLAFS if you ship container images that carry far more than the workload needs, because the convert, profile and debloat cycle is scripted end to end and the paper reports a substantial size reduction on a standard image. Do not adopt it if your container's behaviour varies between the profiling run and production, since files never touched during profiling are removed by design.
- 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 12 days ago.
- What is it written in?
- Mainly Go, 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 tool claims and where the claim comes from
BLAFS is described as a tool for container debloating that removes bloat and improves performance and security, and the README's own headline is that it can shrink your container size up to 95 percent.
The mechanism is stated in one sentence: BLAFS is a bloat-aware filesystem for container debloating. It detects the files used by the container, and then debloats the container by removing the unused files. The debloated containers are still functional and can run the same workload as the original containers, but with a much smaller size and faster deployment.
That is a filesystem-level design rather than a post-processing trick, and the repository layout confirms it. There is an fs directory holding the C implementation of the filesystem, an internal directory for the Go side, a main.go, a _docker directory for the image build, a tests directory, and a dev.sh. The Makefile builds two separate binaries, one called debloated_fs built with CMake out of the fs directory and one called baffs built with the Go toolchain, and the install target copies both into /usr/bin.
The design principles are given as effective, efficient, and easy to use, and there is a research paper behind it, The Cure is in the Cause: A Filesystem for Container Debloating, on arXiv. The README also gives a second citation, for a paper titled BLAFS: A Bloat-Aware Container File System, presented at the 2025 ACM Symposium on Cloud Computing, with Zhang, Alhanahnah, Leitner and Ali-Eldin as authors.
The primary language is Go, the licence is MIT, and the repository is not archived with the last push on 2026-10-12. The release history is short, v0.1.0 from 2025-02-20 and v0.1.1 from 2025-04-25, so this is an early implementation of a published idea rather than a settled tool.
The three step cycle: convert, profile, debloat
The Automating BLAFS section states the cycle in three steps, and this is the whole mental model.
Convert is the first step: it converts the container into the BLAFS filesystem. In the command line this is the shadow subcommand, baffs shadow --images=redis:7.4.1, and the README notes that this converts the filesystem of the redis image to the BLAFS filesystem.
Profiling is the second step, and it is the one that requires you to do the work. You run your workload against the converted container and the filesystem records which files are touched. The README is unusually clear that the choice of workload determines the result: it is recommended to run some extensive workloads, such as the unit tests or integration tests of your container, and in the example, for brevity, they simply start the redis server.
Debloat is the third step: it retains only the files used during profiling and removes everything else. The command is baffs debloat --images=redis:7.4.1, and it generates a new image named redis:7.4.1-baffs, which has a much smaller size.
The example script referenced in the README automates exactly this for Redis: it first converts the container filesystem into BLAFS, uses some integration tests as the profiling workloads to debloat the redis container, then debloats the container according to the profiling workloads, and finally runs the debloated container with the profiling workloads to verify that the debloated one still functions correctly.
That final verification step is the part worth copying. The tool can do the first three stages, but only you can decide whether the profiling workload was representative.
Running the flow with Docker in Docker
The quick start runs the tool from a container, and the mechanics are worth reading because they explain the privileges involved.
The image is pulled with:
docker pull justinzhf/baffs:latestThen it is started in privileged mode so that Docker can run inside Docker, with the host's /tmp/docker mounted at the container's /var/lib/docker:
docker run -d --name baffs --privileged=true -v /tmp/docker:/var/lib/docker justinzhf/baffs:latestThe README explains the mount: all the images pulled inside the baffs container are stored in the host's /tmp/docker, and you can change the path to any other directory you like. You then enter the container with docker exec -it baffs bash, and inside it you pull the image you want to shrink, in the example redis:7.4.1, and run the shadow and debloat commands against it.
The size comparison at the end is the payoff, and the README shows the output of docker images | grep redis with the debloated image at 28.8MB against the original at 117MB for that particular example.
Finally you check that the debloated image still runs, with docker run -it --rm redis:7.4.1-baffs, and the README's own criterion is simple: if the redis server can be started, then the debloating is successful.
Note the naming detail, because it will trip you up when you search for the tool later. The repository is BLAFS, the binaries are baffs and debloated_fs, the Docker image is justinzhf/baffs, and the README refers to a BAFFS filesystem in one place. The module path in go.mod is github.com/negativa-ai/BLAFS, which does not match the repository location.
Shared layers, top layers and the three working modes
The advanced usage section covers the cases where a container is not a single self-contained image.
Debloating multiple images at once is possible when two images share some common layers. The shadow command takes a comma-separated list, with the note that the two images should share some of the same layers initially, and the debloat command takes the same list and debloats both, with shared layers preserved. The reason is size rather than correctness: the debloated images will share the same layers, so the storage saving is not paid twice.
Debloating only certain layers is the serverless case. The README says serverless containers are usually built on top of a base image, and that you can debloat only the unique layers of the serverless container while keeping the base image untouched. The example shows the shadow command for one image and then a debloat command with a --top=3 argument, described as debloating the image with its top 3 layers. Keeping the base image intact matters because that base image is likely shared with other functions and you do not want to fork it.
The README also names three working modes, no-sharing, sharing, and serverless, and says to refer to the paper for the details. That is an honest signal about where the detail lives, and it is the part to read before choosing a mode.
Logging is configurable through two environment variables. LOG_LEVEL sets the logging level for baffs, and SPDLOG_LEVEL sets it for the debloated_fs binary, and both take debug, info, warning or error. Two variables for two processes is a small detail that tells you the implementation is split the same way the Makefile splits the build.
The build, the dependencies and the examples
The Makefile shows that the project is two codebases in one repository. The debloated_fs target runs cmake over the fs directory and builds it, and the baffs target builds the Go module with the buildvcs flag disabled before moving the resulting binary into place. The install target copies both binaries into /usr/bin, and the test target runs the fs test binary and then go test over the whole module, while integration_test depends on install and runs tests/test.sh.
The Go dependencies are small and tell you what the tool talks to. It uses the Docker client at v27.5.1, logrus for logging, stretchr/testify for tests, the Docker distribution and opencontainers image-spec packages, and alexflint/go-arg for the command line parser. The Go version declared is 1.23.6.
The examples directory is where you would look to see whether this fits your workload. There are separate directories for redis, memcached, a pytorch_inference case, shared_layers, a file_reader example and a debloat.py script, plus a README. A PyTorch inference example and a Memcached example side by side with Redis is a good sign, because it suggests the technique was tested against workloads with different shapes, one numeric and one memory and key value.
The paper reference is the place to look for the measured results. The README itself only gives the headline figure of up to 95 percent size reduction and the single Redis example with its before and after sizes, so if you need the full comparison, the arXiv paper is where the data lives.
Where BLAFS is the wrong tool
The design has one fundamental dependency and it is the profiling workload, so that is where the risk lives.
The first limit is that the retained file set is exactly the set your workload touched. Anything the profiling run did not exercise is removed, which is the point of the tool and also its hazard. A container whose behaviour depends on a file that is only read under a rare condition, a configuration file for a code path your tests do not reach, or a locale or certificate bundle used in one region, will work in your test and fail in production. The README's own advice points at the mitigation, run the unit tests and integration tests of your container rather than a trivial command, and the example script's final step, running the debloated image against the same workloads, checks the same thing. Neither is a substitute for understanding which paths your production traffic takes.
The second is operational. The flow requires privileged mode, Docker inside Docker and a writable mount of the host Docker directory. That is a meaningful amount of privilege for a build step in a CI pipeline, and it means the tool cannot run in an unprivileged or rootless environment without changes. For an organisation with strict container isolation, that is a blocker rather than an inconvenience.
The third is the maturity and the naming. The versions are 0.1.0 and 0.1.1, the README mixes BLAFS and BAFFS, the Docker image is under a personal namespace rather than the project organisation, and the go.mod module path does not match the repository URL. Those are all small things individually, and together they say that you should read the code before you depend on it, and that upstreaming the module path and the image is worth doing if you adopt it.
The alternative approach is the obvious one, a multi-stage Dockerfile with a small runtime stage, or distroless and scratch bases, or building from a minimal base image in the first place. The difference in approach is that those methods remove files by construction, at the cost of you knowing in advance what is needed, while BLAFS removes files by observation, which handles the case where you do not know. For a container whose contents are dictated by a third-party base image with no maintained slim variant, observation is the only route, and that is a genuine gap the tool fills.
Editorial conclusion
Adopt BLAFS if you ship container images that carry far more than the workload needs, because the convert, profile and debloat cycle is scripted end to end and the paper reports a substantial size reduction on a standard image. Do not adopt it if your container's behaviour varies between the profiling run and production, since files never touched during profiling are removed by design. Verify first that you can run a profiling workload that exercises the code paths your production traffic reaches, that your runtime has the mount privileges the flow needs, since the tool runs privileged and mounts the host Docker directory, and that the naming is settled, since the README mixes BLAFS and BAFFS and the module path in go.mod is github.com/negativa-ai/BLAFS while the repository sits under reSecureIt.
Frequently asked questions
What is BLAFS and how does it debloat a container?
BLAFS is a bloat-aware filesystem for container debloating. It converts the container into the BLAFS filesystem, records which files a profiling workload touches, and then retains only those files, producing a new image that still runs the same workload at a much smaller size.
How do I install and run BLAFS?
Pull the image with docker pull justinzhf/baffs:latest, then run it privileged with the host Docker directory mounted, so that Docker runs inside Docker and the pulled images land on the host. Inside the container you pull the target image, run baffs shadow on it, run the profiling workload, and then run baffs debloat on it.
What are the baffs shadow and baffs debloat commands?
shadow converts the image's filesystem into the BLAFS filesystem, and debloat produces the reduced image from what was recorded during profiling. The debloat command generates a new image tagged with a -baffs suffix, for example redis:7.4.1-baffs.
Can BLAFS debloat only some layers of an image?
Yes. The --top argument limits debloating to the top layers of an image, and the README presents this as the serverless case, where a function is built on a base image and only its unique layers should be debloated while the base image is left untouched. It also supports debloating several images at once when they share layers.
What are the risks of debloating a container with BLAFS?
The retained file set is exactly the set your profiling workload touched, so a file that is only needed on a code path the workload did not exercise will be removed. The flow also needs privileged mode, Docker inside Docker and a writable mount of the host Docker directory, which is a lot of privilege for a build step.
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/resecureit-blafs)Was this useful?