Open-source project
nothings/stb avatar
nothings/stb

stb: 21 single-file C libraries you copy, diff and maintain yourself

stb single-file public domain libraries for C/C++

34,754 stars8,095 forksCNOASSERTION

At a glance

What is it?
stb is a set of 21 public domain single-file C libraries, from the stb_image loader through stb_truetype and stb_ds, totalling 51166 lines. Integration is one macro in one source file, and the cost is that security bugs are discussed in public, there are no tagged releases, and SIMD is a compile-time choice made per build.
Who is it for?
stb fits a prototype, a game, a build tool, or any C project where adding a dependency is the bigger problem and a 7988-line header is an acceptable answer to it. It does not fit a service with an active security response process, a team that needs a versioned artifact it can pin, or a decode path that has to negotiate SSE2 at runtime.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 60 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 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Exactly one source file may define STB_IMAGE_IMPLEMENTATION

The mechanism that trips up newcomers here is not a function, it is a macro. The .h files in this repository declare the functions they contain but do not compile any code on their own, so a translation unit that includes stb_image.h ends up with declarations and nothing else. To get the definitions, exactly one C or C++ source file in your build has to define the implementation macro, and for the image loader that pair of lines is:

c
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

The correct macro for each library is named at the top of that library, so the name itself is never a guess. The exclusivity is on you, and the word exactly is the load-bearing part: the guidance is one file, not one file per library that happens to need it. It also asks for a file you do not edit frequently, which in a large C project means your build system needs a designated home for vendored implementation code while every other file keeps its include bare. The headers do not enforce that arrangement on your behalf, so a build that picks up one extra file is a problem you find at compile time rather than a warning you get for free.

Security bugs are argued over in public, and merges can take significant time

The first substantive paragraph in this repository is a warning, and it is unusual to find one placed that prominently. Security-relevant bugs are discussed in public, in GitHub Issues and Pull Requests, and fixes may take significant time to be implemented or merged. The instruction that follows is direct: if that risk is unreasonable for your project, do not use stb libraries. Treat that as a decision rule rather than boilerplate. Because the discussion happens in the open tracker, the shape of a flaw is visible to anyone watching it before a patched file exists, so the window in which a network-facing decoder sits on a known bug is not something a release note will close for you. There are no GitHub releases here either, so there is no stream of version bumps to watch for the moment a fix lands. The tree does carry a SECURITY.md file, and a fix, when it arrives, reaches you as a new copy of a header inside a directory you control. For an offline tool that trade is fine. For a service that decodes untrusted images or fonts on someone else's behalf, the open window is the thing to weigh first.

No tagged releases exist, so the version lives in the file you copied

This repository has no GitHub releases at all, which means no tag, no project version and no changelog to pin against. What exists instead is a version carried per library and echoed in a table, and that table sits in a README marked as automatically generated and not to be changed by hand. It is the closest thing to an index: stb_image at 2.30, stb_truetype at 1.26, stb_image_write at 1.16, stb_textedit at 1.14, stb_sprintf at 1.10, stb_ds at 0.67, stb_divide at 0.94, stb_connected_components at 0.96, and at the low end stb_leakcheck at 0.6 and stb_include at 0.02, alongside a total of 21 libraries and 51166 lines of C. Read that as a snapshot of one branch rather than a release channel. The consequence is concrete: upgrading means copying a new file over an old one and reading the diff yourself, because no package manager will tell you what changed. A copy of stb_image.h in your source tree is a fork with no upstream tracking until you build that tracking yourself.

stb_image takes SSE2 or nothing, because runtime detection was abandoned

stb_image does not test the processor at runtime, and the reason is a dead end the author documented and gave up on. It will use SSE2 if you compile with -msse2, and otherwise it will not use any SIMD at all, rather than detecting the CPU and handling it correctly. The obstacle is structural: the approved path in GCC for runtime detection requires multiple source files, one for each CPU configuration, and stb_image is a header library that compiles in a single source file, so there is no approved way to build both an SSE-enabled and a non-SSE variation at once. Workarounds were attempted and dropped after specific gcc versions repeatedly broke them, and the discussion sits in issues 280 and 410. What this costs is that the decision happens at compile time rather than at startup. One binary has to serve every machine it lands on, so a deployment spanning pre-SSE2 hardware and modern CPUs means two artifacts or an unsupported target. The flip side is that a binary built with -msse2 for every machine will not take an illegal instruction on an older CPU, which is worth having when the alternative is a decode path that guesses.

The project says these libraries may be slower and less featureful

The comparison question every newcomer asks has an answer here, and the answer is no. These libraries are better only in that they are easier to integrate, easier to use and easier to release: a single file, a good API, no attribution requirement. They may also be less featureful, slower, and use more memory. If you are already using an equivalent library, the stated position is that there is probably no good reason to switch. Take the image loader as the concrete case. stb_image decodes JPG, PNG, TGA, BMP, PSD, GIF, HDR and PIC from a file or from memory, which is a wide format list, but it replaces a codec library rather than wrapping one, and the table does not itemise what any of those format decoders leave out. If your pipeline depends on a specific color profile, a specific chroma subsampling mode or a specific PNG feature, you have to read the file to find out, because the index will not tell you. The advantages on offer are integration advantages, and they are real, but they are advantages against a build file rather than against a decoder.

Four files in the table came from other authors, and the licence is per file

Four of the listed files did not begin as this author's code. stb_dxt is by Fabian "ryg" Giesen, the original stb_image_resize is by Jorge L. "VinoBS" Rodriguez, and stb_image_resize2 along with stb_sprintf are by Jeff Roberts. That matters for licensing, because the guarantee offered is a per-file one: the libraries are public domain, they are also available under the MIT open source licence for anyone whose lawyers dislike public domain, and every source file includes an explicit dual-licence to choose from. Nothing makes that guarantee blanket across the twenty-one libraries, so a licence audit has to be done file by file instead of once for the project. It also explains the shape of the tree. The top level carries stb_image_resize2.h and not the original stb_image_resize, and there is a deprecated/ directory sitting alongside docs/, tools/, tests/ and data/, so superseded headers have somewhere to go. If your policy is one vendored dependency with one origin story, this repository does not offer one, and those four files are the ones to check first.

The lines-of-code column is a warning label, not a quality score

One column in that table is defended in advance, and the defence is worth reading before you use the numbers. The entry asks why lines of code are listed, calls the metric terrible, and answers that it is there to give an idea of the internal complexity of a library, to help you manage your expectations, and to let you know what you are getting into. Not every library is written in the same style, but the styles are similar enough that comparisons between them are still meaningful. The spread makes the point. At the top, stb_image_resize2.h runs to 10679 lines and is described as resizing with good quality, stb_image.h is 7988, stb_vorbis.c is 5584 and stb_truetype.h is 5079. At the bottom, stb_easy_font.h is 305 lines and stb_leakcheck.h is 194, and both of those are described as quick-and-dirty. So the phrase single file tells you nothing about how much code you are adopting, and a 194-line header is a different kind of commitment from a 10679-line one. Read the number next to the description rather than on its own, because the description is the part telling you whether the speed and the memory suit your use.

Editorial conclusion

stb fits a prototype, a game, a build tool, or any C project where adding a dependency is the bigger problem and a 7988-line header is an acceptable answer to it. It does not fit a service with an active security response process, a team that needs a versioned artifact it can pin, or a decode path that has to negotiate SSE2 at runtime. Before you commit, read the security paragraph that opens the README, check the implementation macro named at the top of the header you plan to copy, and diff upstream against the copy already sitting in your tree.

Frequently asked questions

What are STB libraries?

Single-file public domain or MIT licensed libraries for C and C++, 21 of them in the current tree, covering image loading and writing, image resizing, truetype font rasterization, Ogg Vorbis decoding, typesafe containers, fast sprintf, and assorted graphics and game development helpers. Together they come to 51166 lines of C.

What is STB_Image?

stb_image is the image loading and decoding header, currently listed at version 2.30 and 7988 lines, reading JPG, PNG, TGA, BMP, PSD, GIF, HDR and PIC from a file or from memory. It is one of the five the project calls noteworthy, alongside the writer, the resizer, stb_truetype and stb_ds.

Can I relicense stb code inside my own library?

Yes. Because the code is public domain, you can freely relicense it to whatever license your new library wants to be, with no obligation to the original author. Every source file also carries an explicit dual-licence, public domain or MIT, for you to pick from.

Should I replace my existing image library with stb_image?

The project says there is probably no good reason to switch if you already use an equivalent library. The stated advantage is easier integration, easier use and easier release through a single file, and the stated cost is that these libraries may be less featureful, slower, or use more memory.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
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/nothings-stb.svg)](https://hysenlabs.com/projects/nothings-stb)