nbstripout: Keeping Notebook Output Out of Git
strip output from Jupyter and IPython notebooks
At a glance
- What is it?
- nbstripout is a Python command-line filter that removes notebook output before Git records a file. It suits teams that want executable notebooks with local results while avoiding committed outputs and output-heavy diffs.
- Who is it for?
- nbstripout is appropriate for developers who execute Jupyter or IPython notebooks but do not want outputs in version control. It is not appropriate when outputs are intended to be committed or when the project requires a documented metadata-cleaning policy it does not specify.
- 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?
- Activity is slowing. The repository last received commits 6 months 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 October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The notebook-output problem nbstripout addresses
nbstripout addresses a specific source of noisy Git history: executed Jupyter and IPython notebooks can retain text output, execution details, and other content that developers generally do not want to review or store. A notebook may still be useful locally with its current output visible, even when the repository should contain only the source structure needed to run it. The README describes its behavior as roughly equivalent to the notebook interface's "Clear All Output" command, but "only visible to Git." In other words, the working file can retain output while the version-control representation is cleaned.
The intended users are developers working with `.ipynb` files and related notebook formats who want smaller diffs and smaller repository contents. It also supports Zeppelin notebooks through its Zeppelin mode. This makes it useful where a team wants the same policy across notebook workflows, although the README does not document every metadata field removed. That omission matters. A tool that changes notebook JSON before it enters Git should have an explicit policy for attachments, kernels, language metadata, signatures, and similar fields, but the README only says that nbstripout strips output and "some metadata."
The distinction from automatically clearing a notebook inside Jupyter is important. Jupyter's interface command changes the working document. nbstripout can instead preserve the developer's local output while producing a cleaned version only when Git processes the file. That is a better fit for repositories where output is evidence of a local run rather than source code to preserve.
File, stdin, and stdout processing in nbstripout
The documented processing model is straightforward. nbstripout reads a notebook from a named file or standard input, strips output and selected metadata, and writes the cleaned notebook back to the original file or to standard output. With ordinary file arguments it modifies files in place. With input piped into it, the cleaned JSON can be redirected to another file. The README also gives a form that sends the cleaned notebook directly to another command.
File-extension recognition controls normal processing. `.ipynb` files are accepted without an additional mode, while `.zpln` files use Zeppelin mode. An extension such as `.ipynb.bak` would otherwise look nonstandard, so `-f` forces processing of a non-`.ipynb` filename. For a non-Zeppelin extension that actually contains a Zeppelin notebook, `-m zeppelin` selects the parser mode explicitly. These options make the tool more useful for backups, generated files, and repositories with custom notebook extensions, but they also place responsibility on the caller to choose the correct mode.
For Git use, `nbstripout --install` registers the required Git filter and matching attributes. Git then routes relevant notebook files through nbstripout while leaving output available in the local working copy. The filter is declared as `required`, which means a filter failure or misconfiguration is not silently ignored. That is a useful constraint for reproducibility because a broken filter cannot quietly admit unfiltered notebook content. It also means an unavailable interpreter, bad installation, or incorrect configuration can make Git operations fail instead of succeeding with the wrong filter behavior.
Installing nbstripout and running a first notebook filter
The README directs users to PyPI for installation. This upgrades nbstripout in the current Python environment:
pip install --upgrade nbstripoutFor an Anaconda Python distribution, the documented alternative uses conda-forge:
conda install -c conda-forge nbstripoutThe project metadata in `pyproject.toml` requires Python 3.10 or later. Version 0.9.1 is the current package version stated there. After installation, a safe first operation is a dry run. It reports which files would be stripped without modifying them:
nbstripout --dry-run FILE.ipynb [FILE2.ipynb ...]If that identifies the intended file, strip it directly:
nbstripout FILE.ipynb [FILE2.ipynb ...]This operation modifies the specified notebook in place. A caller that needs to retain the original file should use the verification form before committing or remove and restore the file separately. The README does not document a backup flag for direct file processing.
For an existing Git repository, configure the local filter and attributes:
nbstripout --installWithout extra flags, the filter is written to `.git/config`, and attributes are written to `.git/info/attributes`. The repository can therefore adopt the behavior without committing global configuration or changing a shared `.gitattributes` file. Configuration should be checked with:
nbstripout --statusThe command exits with code 0 when the filter is installed in the current repository and code 1 otherwise.
Repository-local, global, and shared Git filter configuration
nbstripout offers several installation scopes, and the selected scope changes both who receives the filter and whether configuration is committed. Repository-local installation writes Git filter settings to `.git/config` and attributes to `.git/info/attributes`. This is the narrowest documented option and requires every repository to be configured explicitly.
To commit the attribute declaration in the repository, use an explicit attributes path:
nbstripout --install --attributes .gitattributesThe README recommends per-repository installation so a project can choose where it applies. It also says the attributes file can be committed. The configuration table confirms that `--attributes=.gitattributes` places filter configuration in `.git/config` while placing attributes in `.gitattributes`. That separation matters: the executable filter setup remains local, whereas the tracked file tells Git which paths need filtering.
Global installation targets `~/.gitconfig` and `~/.config/git/attributes`. System-wide installation targets `$(prefix)/etc/gitconfig` and `$(prefix)/etc/gitattributes`, and the README notes that most installations will require `sudo`:
nbstripout --install --global[sudo] nbstripout --install --systemA repository that expects identical behavior on several machines may prefer the committed `.gitattributes` option. Global or system installation is less appropriate when behavior should remain opt-in. The actual Git command records the interpreter path used during installation by default. Machines with different Python layouts can fail if they cannot resolve it. The README offers `--python python3` to let each machine locate its own interpreter, while also warning that some setups require an absolute path and that automatic resolution may select an unwanted Python version.
Check or remove the setup with the documented commands:
nbstripout --is-installednbstripout --uninstall --attributes .gitattributesThe uninstall command removes both the filter and the matching attributes from the selected location.
Dry runs, verification, and recursive processing safeguards
nbstripout provides three distinct inspection or modification patterns. In-place processing changes notebook files. Standard-output processing leaves the source stream available for redirection or another command. Dry-run processing lists files that would be changed, while verification behaves like a dry run but returns failure when a file would have been stripped. That difference is significant in continuous integration: `--dry-run` can inform a person, whereas `--verify` can enforce the policy automatically.
A recursive local sweep is documented as follows:
find . -name '*.ipynb' -exec nbstripout {} +This command changes every matching notebook under the current directory. There is no confirmation prompt in the documented invocation. A reviewer who wants to inspect affected files first should run `nbstripout --dry-run` with the same file set instead.
Piped input supports workflows where Git or another tool needs the cleaned bytes rather than a modified file:
cat FILE.ipynb | nbstripout > OUT.ipynbThe README also documents direct piping to another command:
nbstripout -t FILE.ipynb | other-commandNo implementation details in the README describe how nbstripout preserves JSON formatting, handles invalid notebooks, or recovers from interrupted writes. Those behaviors should not be assumed. The `tests/` directory and `pytest.ini` indicate that the repository has automated tests, but the repository listing does not provide enough test results or coverage details to make a claim about malformed input, very large notebooks, or compatibility with every notebook schema version.
Zeppelin support, pre-commit files, and compatibility boundaries
The command-line interface includes explicit Zeppelin support. A `.zpln` filename can be passed directly, while another extension can be forced into Zeppelin mode. Standard-output processing supports the same format:
cat FILE.zpln | nbstripout -m zeppelin > OUT.zplnThis is narrower than saying every notebook ecosystem is supported. The README specifically names Jupyter, IPython, and Zeppelin, and the repository topics also include Jupyter and IPython notebook terms. No adapter for other notebook formats is documented.
The repository contains `.pre-commit-hooks.yaml` and `.pre-commit-config.yaml`, which shows that pre-commit integration is part of the project layout. The visible README section is truncated before it provides the complete pre-commit procedure, so this review does not invent hook identifiers or configuration keys. A user wanting that integration must consult those repository files and the full README rather than infer settings from the general Git-filter examples.
Python compatibility is a hard boundary. Version 0.4.0 and later support Python 3 only, while `pyproject.toml` requires Python 3.10 or later. The README separately says Python 2.7 users should install `nbstripout==0.3.10`. That legacy version is not interchangeable with the current package requirement. Users should also account for a Git operation failing when the configured interpreter cannot run the required filter.
License metadata, maintenance activity, and upgrade work
The repository is not archived, and its last push was on 2026-04-11. Recent package releases listed for the project are 0.9.1 on 2026-02-21, 0.9.0 on 2026-01-17, and 0.8.2 on 2025-11-16. These dates and the project metadata are concrete signals available for release planning, although they do not by themselves document the scope or compatibility impact of each upgrade.
There is a licensing metadata discrepancy that should be resolved before redistribution. The repository-level classification describes the license as a custom license that GitHub cannot classify and directs readers to `LICENSE.txt`. Meanwhile, `pyproject.toml` declares `license = "MIT"`, points to `LICENSE.txt`, and lists Python versions through 3.14. Package metadata therefore presents the project as MIT, but the full text of `LICENSE.txt` is not included in the repository listing. This is not legal advice. The relevant verification step is to read `LICENSE.txt` and confirm that it matches the packaging declaration before copying code or distributing a modified package.
The dependency list in `pyproject.toml` contains `nbformat`, so notebook-format compatibility can change when that dependency changes even if nbstripout itself is not modified. Upgrade planning should account for both nbstripout and nbformat, especially when a repository enforces a narrow Python version or checks notebooks in CI.
nbstripout compared with clearing notebooks inside Jupyter
The closest documented alternative is Jupyter's "Clear All Output" command. Both approaches remove output from a notebook, but they act at different boundaries. Clearing output inside the notebook interface changes the working document itself. nbstripout can preserve the developer's local output while exposing a cleaned version to Git. That difference supports exploratory work where output is useful to the person running the notebook but noisy or inappropriate for version control.
Another alternative is a separate one-time command or script that rewrites every notebook before commit. nbstripout provides a narrower, existing mechanism for direct processing, stdin and stdout pipelines, dry runs, verification, and required Git filters. The trade-off is that its metadata policy is only described as stripping output and "some metadata." A custom script may be preferable when a project must define exactly which attachments, execution counts, signatures, or other fields are retained, provided someone owns and tests that script. The README does not claim that nbstripout preserves selected metadata fields or supports a configurable metadata allowlist.
For organizations that already standardize on clearing notebooks manually, nbstripout may remove a repetitive step. For repositories where rendered results, plots, or executed cell output are part of the artifact, nbstripout is the wrong default because it is designed to remove that content.
Editorial conclusion
nbstripout is appropriate for developers who execute Jupyter or IPython notebooks but do not want outputs in version control. It is not appropriate when outputs are intended to be committed or when the project requires a documented metadata-cleaning policy it does not specify. Before adoption, check LICENSE.txt, confirm Python 3.10 or later, and run `nbstripout --verify` against representative notebooks.
Frequently asked questions
Does nbstripout remove notebook output without changing the working file?
Yes, that is the Git-filter use described by the README. The local notebook can retain output while Git receives a cleaned version through the configured required filter.
Which Python versions does the current nbstripout require?
The current `pyproject.toml` declares `requires-python = ">=3.10"`. The README also notes that Python 2.7 requires the older `nbstripout==0.3.10` release.
How can I check whether a notebook would be changed before stripping it?
Use `nbstripout --dry-run FILE.ipynb` to list files that would be stripped without modifying them. Use `nbstripout --verify FILE.ipynb` when the command should fail if the file would be stripped.
Can nbstripout be used as a pre-commit hook?
The repository contains `.pre-commit-hooks.yaml` and `.pre-commit-config.yaml`, indicating pre-commit support in the project layout. The README excerpt does not include the complete hook configuration, so consult those files for the exact hook identifier and settings.
Does nbstripout support Zeppelin notebooks?
Yes. The README documents direct processing of `.zpln` files and the `-m zeppelin` option for files with other extensions.
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/kynan-nbstripout)Was this useful?