ox-ipynb is an Org-mode exporter that converts org-mode files to Jupyter notebooks (.ipynb format). It provides a seamless workflow for authoring computational notebooks in Org-mode while maintaining compatibility with the Jupyter ecosystem.
Jupyter notebooks consist of two basic cell types: markdown cells (for text, math, images) and code cells (for executable code with results). This exporter intelligently parses org-mode content into these cell types, preserving formatting, structure, and executable code blocks.
Key Features:
- Multiple language kernels: Python, R, Julia, Clojure
- Rich markdown export: LaTeX math, tables, images, links
- Table of contents generation
- Citations (org-cite and org-ref)
- Slideshow support (RISE)
- Cell and notebook metadata control
- Participant notebooks (strips solutions/hidden content)
- Export variations (with/without results)
- Emacs 30+
- Org-mode 9.7+
- Jupyter (for viewing/running notebooks)
- Clone or download this repository
- Add to your Emacs configuration:
(add-to-list 'load-path "/path/to/ox-ipynb")
(require 'ox-ipynb)- The export menu will be available in any org-mode buffer via
C-c C-e n
- Create an org-mode file with code blocks:
#+TITLE: My First Notebook
#+AUTHOR: Your Name
* Introduction
This is a markdown cell.
print("Hello, Jupyter!")
- Export using
C-c C-e n o(export to notebook and open)
The export menu (C-c C-e n) provides several options:
| Key | Command | Description |
|---|---|---|
| b | Export to buffer | View JSON in Emacs buffer |
| n | Export to notebook | Save as .ipynb file |
| o | Export to notebook and open | Save and open in Jupyter |
| p | Export to participant notebook | Remove solutions and hidden content |
| r | Export without results and open | Strip all code results before export |
| s | Export to slides and open | Convert to RISE slideshow |
ox-ipynb supports multiple Jupyter kernels. Specify the language in your code blocks:
import numpy as np print(np.array([1, 2, 3]))
Or use ipython as the language name (legacy support).
library(ggplot2) summary(iris)
Requirements: R, IRkernel package, and R kernel registered with Jupyter.
using Statistics mean([1, 2, 3, 4, 5])
(map inc [1 2 3 4 5])
Requirements: Clojupyter kernel installed.
If the first code block doesn’t match your notebook language, use:
#+OX-IPYNB-LANGUAGE: jupyter-python
To add support for new languages, extend ox-ipynb-kernelspecs and ox-ipynb-language-infos variables. See the existing definitions in ox-ipynb.el as examples.
Code blocks are exported as code cells. Results are automatically included:
x = [1, 2, 3, 4, 5] sum(x) #+RESULTS: : 15
# This block won't appear in the notebook
secret_config = "hidden"
# This block shows code and results (default)
print("Visible output")
Options: code, results, both (default), none
Org-mode tables export as markdown tables:
| Name | Score | Grade | |---------+-------+-------| | Alice | 92 | A | | Bob | 85 | B | | Charlie | 78 | C |
Tables with headers and complex formatting are preserved correctly. Recent improvements (Issue #23) ensure proper markdown table structure.
Inline math and display equations are supported:
The equation $E = mc^2$ is Einstein's mass-energy equivalence.
The integral is:
$$\int_{0}^{\infty} e^{-x^2} dx = \frac{\sqrt{\pi}}{2}$$
Special handling prevents dollar signs in tables from being interpreted as math (Issue #81387fd).
Visit [[https://jupyter.org][Jupyter Project]] for more information.
Cross-references between sections work:
See [[*Introduction][the introduction section]] for background.
[[file:plot.png]]
Images are embedded as base64-encoded data for portability. Matplotlib plots generated in code cells are automatically captured.
Enable automatic TOC generation:
#+OPTIONS: toc:t
Control depth:
#+OPTIONS: toc:2
The TOC is inserted as a markdown cell with clickable navigation links.
ox-ipynb supports two citation systems:
Modern Org 9.5+ citation system:
#+BIBLIOGRAPHY: references.bib According to [cite:@smith2020], the results show... #+PRINT_BIBLIOGRAPHY:
Citations are formatted as “(Author et al. YEAR)” and the bibliography is generated automatically.
Traditional org-ref package:
bibliography:references.bib According to cite:smith2020, the results show...
Configuration required:
(setq ox-ipynb-preprocess-hook
'((lambda () (org-ref-csl-preprocess-buffer 'html))))See examples/07-citations-org-cite.org and examples/08-citations-org-ref.org.
Add metadata to individual cells using #+attr_ipynb::
#+attr_ipynb: :tags ["important" "review"] result = compute_critical_value()
This is preserved in the notebook JSON and can be used by Jupyter extensions.
Add custom metadata to the entire notebook:
#+OX-IPYNB-NOTEBOOK-METADATA: (rise . ((autolaunch . t) (scroll . t)))
Useful for slideshow settings (RISE), execution control, and extensions.
Export specific org-mode keywords to notebook metadata:
#+OX-IPYNB-KEYWORD-METADATA: AUTHOR DATE DESCRIPTION #+TITLE: My Notebook #+AUTHOR: John Doe #+DATE: 2025-01-15 #+DESCRIPTION: Analysis of experimental data
These keywords are stored in the notebook metadata’s org section.
Create presentations using Jupyter RISE extension:
#+OX-IPYNB-NOTEBOOK-METADATA: (rise . ((autolaunch . t))) * Title Slide #+attr_ipynb: (slideshow . ((slide_type . slide))) Introduction content * Main Point #+attr_ipynb: (slideshow . ((slide_type . slide))) Main content ** Details #+attr_ipynb: (slideshow . ((slide_type . subslide))) Additional details
Slide types: slide, subslide, fragment, skip, notes
Helper function: M-x ox-ipynb-insert-slide inserts the attribute line interactively.
Create student/participant versions by automatically removing solutions and instructor notes:
def calculate_mean(data):
### BEGIN SOLUTION
return sum(data) / len(data)
### END SOLUTION
pass # Student implements here
Export with C-c C-e n p to strip:
### BEGIN SOLUTION ... ### END SOLUTIONregions### BEGIN HIDDEN ... ### END HIDDENregions- Elements marked with
#+attr_ipynb: :remove t
Create clean notebooks without cluttering output:
Export with C-c C-e n r to remove all #+RESULTS: blocks before export. Useful for:
- Sharing notebooks for others to run fresh
- Version control (cleaner diffs)
- Reducing file size
Control what content is exported:
#+EXCLUDE_TAGS: noexport private * Public Section This will be exported. * Private Notes :private: This section won't appear in the notebook.
#+SELECT_TAGS: publish * Draft Section Not exported (no tag). * Published Analysis :publish: This will be exported.
The exporter handles broken or special links gracefully:
#+OPTIONS: broken-links:mark
Options: nil (error), t (ignore), mark (mark as broken)
Particularly useful when using citation links or other special link types.
Org-babel noweb references are expanded during export:
<<setup>> <<analysis>> <<visualization>>
Customize export behavior with hooks:
(setq ox-ipynb-preprocess-hook
'(my-custom-processing-function))Common uses:
- Citation processing (org-ref-csl-preprocess-buffer)
- Custom transformations
- Cleanup operations
Built-in preprocessing functions:
ox-ipynb-preprocess-ignore- Remove:ignore:tagged headingsox-ipynb-preprocess-babel-calls- Remove babel callsox-ipynb-remove-solution- Strip solution regionsox-ipynb-remove-hidden- Strip hidden regionsox-ipynb-remove-remove- Remove marked elements
Control the output filename:
#+EXPORT_FILE_NAME: my-notebook.ipynb
Use property drawers:
* My Section :PROPERTIES: :EXPORT_FILE_NAME: section-notebook.ipynb :END:
(let ((export-file-name "custom-name.ipynb"))
(ox-ipynb-export-to-ipynb-file))Integrate with org-publish:
(setq org-publish-project-alist
'(("notebooks"
:base-directory "~/org/notebooks/"
:publishing-directory "~/public/notebooks/"
:publishing-function ox-ipynb-publish-to-notebook)))The examples/ directory contains comprehensive demonstrations:
| Example | Feature |
|---|---|
| 01-basic.org | Basic export workflow |
| 02-exclude-tags.org | Tag-based filtering |
| 03-broken-links.org | Link handling |
| 04-tables.org | Table export |
| 05-latex-math.org | Mathematical expressions |
| 06-links-images.org | Links and images |
| 07-citations-org-cite.org | Citations (org-cite) |
| 08-citations-org-ref.org | Citations (org-ref) |
| 09-toc-export.org | Table of contents |
| 10-metadata-cells.org | Cell metadata |
| 11-slideshow.org | RISE slideshows |
| 12-languages-r.org | R language support |
| 13-noweb.org | Noweb expansion |
| 14-participant.org | Participant notebooks |
| 15-no-results.org | Export without results |
| 16-custom-notebook-metadata.org | Notebook metadata |
| 17-diagram-exports-results.org | Diagram exports |
See examples/README.org for detailed documentation.
Export multiple org files:
(ox-ipynb-export-org-file-to-ipynb-file "notebook.org")Works in Dired: mark files and run M-x ox-ipynb-export-org-file-to-ipynb-file
;; Export to buffer
(ox-ipynb-export-to-ipynb-buffer)
;; Export to file
(ox-ipynb-export-to-ipynb-file)
;; Export and open
(ox-ipynb-export-to-ipynb-file-and-open)
;; Export subtree
(ox-ipynb-export-to-ipynb-file nil t)Ensure ox-ipynb is loaded: (require 'ox-ipynb)
Add language to ox-ipynb-kernelspecs and ox-ipynb-language-infos. A warning message will indicate missing languages.
- Check file paths (relative paths work best)
- Ensure images exist before export
- Matplotlib plots should use
plt.show()
- Jupyter requires MathJax (usually included)
- Use
$...$for inline,$$...$$for display math - Avoid dollar signs in non-math contexts
- org-cite: Requires
oc.eland bibliography file accessible - org-ref: Requires preprocessing hook configuration
- Check
.bibfile paths are correct
Enable verbose output:
(setq org-export-with-broken-links 'mark)Check the *Messages* buffer for warnings and errors.
Recent improvements (see git log for details):
- 2025: Support for
:exportsparameter in source blocks - 2025: Fixed table export (removed extra horizontal rules)
- 2025: Custom notebook-level metadata support
- 2025: Clojure/Clojupyter language support
- 2025: Warning when language not in kernelspecs
- 2025: Comprehensive example suite added
- 2025: Metadata preservation through intermediate export
- 2025: TOC duplication fixes
- 2025: Removed s.el and dash.el dependencies
See commit history for complete changelog.
Contributions welcome! Please:
- Add tests/examples for new features
- Update this README
- Follow existing code style
- Submit pull requests to https://github.com/jkitchin/ox-ipynb
GPL v2 or later. See source file for details.
- Repository: https://github.com/jkitchin/ox-ipynb
- Jupyter: https://jupyter.org
- Org-mode: https://orgmode.org
- John Kitchin’s Blog: https://kitchingroup.cheme.cmu.edu