skops: Persisting scikit-learn Models Without pickle, and Generating Model Cards
skops is a Python library helping you share your scikit-learn based models and put them in production
At a glance
- What is it?
- skops is a Python library with two parts: skops.io, which saves and loads scikit-learn estimators without pickle, and skops.card, which builds a model card that can serve as the README.md on the Hugging Face Hub. The security argument is real; the coverage of custom estimators is the part to check before adopting.
- Who is it for?
- Adopt skops.io if you load model files that cross a trust boundary and your estimators are built from scikit-learn classes, and adopt skops.card if the model is published on the Hugging Face Hub and needs a README.md. Do not adopt it as a drop-in pickle replacement for a pipeline full of in-house transformer classes without first running skops.io.get_untrusted_types on a real artifact and confirming every entry is one you can vouch for.
- 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 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The pickle problem skops.io is aimed at
A scikit-learn model saved with pickle is a program, not a data file. Loading it executes whatever the file says to execute, which is why the standard advice is never to unpickle an artifact you did not create. That advice is easy to state and hard to follow: model registries, shared buckets and downloaded checkpoints all involve files that arrived from somewhere else. skops.io is the project's answer. The README describes it as "Secure persistence of sklearn estimators and more, without using pickle." The target user is the engineer who has to move a fitted estimator between machines and cannot assume the file is trustworthy. The second half of the library, skops.card, targets a different moment: documenting what a model does and how it should be used, with output shaped so it can be stored as the README.md on the Hugging Face Hub.
What skops.io writes instead of a pickle stream
The mechanism is a serialization format built from types the library knows how to reconstruct, rather than a bytecode stream that reconstructs arbitrary objects. Because the loader only rebuilds recognized types, a file that names a type outside that set is a decision point rather than an automatic execution. The library exposes this through an inspection step: skops.io.get_untrusted_types returns the types present in a file that skops does not treat as safe by default. If that list is empty, loading is straightforward. If it is not, you either confirm the listed types are ones you trust and pass them to the loader, or you refuse the file. That is the whole security model in one call, and it is a better default than pickle's, which offers no equivalent checkpoint. The trade-off is coverage: a pipeline that ends in a custom transformer class defined in your own package will appear in that untrusted list, so every such class has to be enumerated at every load site. The documentation covers this under persistence, and the exact loader signature and the accepted form of the trusted-types argument should be read there rather than guessed, because the library has changed across releases.
Installing and the two entry points
Installation is a single command: python -m pip install skops. From there the library splits cleanly. The persistence documentation lives at skops.readthedocs.io under persistence.html, and the model card documentation under model_card.html. The model card side produces a card object from a fitted estimator plus optional metadata, and the README states the card can then be stored as the README.md file on the Hugging Face Hub, with pre-populated metadata so the Hub understands the model. That metadata detail matters more than it sounds: a Hub model repository without the expected front-matter fields is just a folder of files, and having the card generator emit them removes a manual step that people skip. The README points to the documentation for complete examples covering both features, which is where the actual constructor arguments and metadata fields are specified. Nothing in the supplied material gives a worked command sequence for either feature, so treat the docs as the source for exact signatures.
Where the no-pickle guarantee costs you
The failure mode is not that skops.io breaks; it is that it refuses, and the refusal arrives at load time in production rather than at save time in development. If a colleague fits a model containing a class skops does not recognize, the artifact saves without complaint and fails to load on the other side unless the type is explicitly trusted. The inspection call is the mitigation, and it belongs in CI against a real artifact, not in a code review comment. There is a second case where skops is the wrong tool: when the artifact is not a scikit-learn estimator at all. A PyTorch checkpoint, a tokenizer directory or a raw NumPy array has no reason to go through this library. skops.io is scoped to sklearn estimators and the objects around them, and using it as a general object serializer means maintaining a trust list for types the library was never designed to describe.
skops.io against joblib and plain pickle
joblib is the practical alternative, and it is what scikit-learn itself recommends for persistence. joblib handles large NumPy arrays efficiently and preserves the familiar pickle semantics, which is exactly the property skops.io gives up. The difference is not speed or convenience. It is that joblib's loader will reconstruct whatever the file names, so a malicious artifact is indistinguishable from a legitimate one at load time, while skops.io makes the type set visible before anything is reconstructed. If your model files never leave a machine you control, joblib is the lower-friction choice and there is no security argument for switching. If they do cross a boundary, the inspection step is the reason to switch, and the cost is the trusted-types list you now maintain. Those two facts pull in opposite directions, and the right answer depends on where your artifacts travel, not on which library is better in the abstract.
Release cadence and what an upgrade costs you
The recent releases are v0.11.0 in December 2024, v0.12.0 in July 2025 and v0.13.0 in August 2025. The gap between v0.11.0 and v0.12.0 is roughly seven months; v0.13.0 followed about two weeks later. Pre-1.0 version numbers mean the API can move, and for a persistence library the artifact format is the part that matters. An upgrade that changes how types are recorded can leave previously written files needing a different load path. The repository is not archived and the last push is dated 2026-08-31, so the project is active, but activity is not the same as format stability and should not be treated as such. Any team pinning skops in a production loading path should keep a fixture artifact from the version that wrote it and re-run the load in CI after every bump. The licence is MIT, which is permissive and places few obligations on redistribution, but note that skops.card writes a README.md intended for publication on the Hugging Face Hub, so the licence of the model and the licence of the library are separate questions. Nothing here is legal advice; read the MIT text and your own model's terms.
Editorial conclusion
Adopt skops.io if you load model files that cross a trust boundary and your estimators are built from scikit-learn classes, and adopt skops.card if the model is published on the Hugging Face Hub and needs a README.md. Do not adopt it as a drop-in pickle replacement for a pipeline full of in-house transformer classes without first running skops.io.get_untrusted_types on a real artifact and confirming every entry is one you can vouch for. Verify that before you migrate any production loading path.
Community notes