Edit anywhere
Open notebooks in VS Code, PyCharm, Vim — any editor, with full language tooling.
Jupytext saves Jupyter notebooks as .py or .md files — easy to edit in any IDE, friendly to version control, and trivial for AI assistants to read and refactor.
# %% [markdown]
# # Quarterly Sales
# A look at Q4 revenue by region.
# %%
import pandas as pd
df = pd.read_csv("sales.csv")
# %%
df.groupby("region")["revenue"].sum().plot.bar()Explicit # %% cell markers — understood by VS Code, PyCharm, Spyder, supported in 30+ languages.
# # Quarterly Sales
# A look at Q4 revenue by region.
import pandas as pd
df = pd.read_csv("sales.csv")
df.groupby("region")["revenue"].sum().plot.bar()Minimal markers — barely looks different from a regular script. Use py:nomarker to drop them entirely.
import marimo
app = marimo.App()
@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
# Quarterly Sales
A look at Q4 revenue by region.
""")
return
@app.cell
def _():
import pandas as pd
df = pd.read_csv("sales.csv")
return (df,)
@app.cell
def _(df):
df.groupby("region")["revenue"].sum().plot.bar()
return
@app.cell
def _():
import marimo as mo
return (mo,)
if __name__ == "__main__":
app.run()Each cell becomes a reactive function — open the file directly in Marimo.
# Quarterly Sales
A look at Q4 revenue by region.
```python
import pandas as pd
df = pd.read_csv("sales.csv")
```
```python
df.groupby("region")["revenue"].sum().plot.bar()
```Plain GitHub Markdown — prose-first, readable everywhere.
# Quarterly Sales
A look at Q4 revenue by region.
```{code-cell}
import pandas as pd
df = pd.read_csv("sales.csv")
```
```{code-cell}
df.groupby("region")["revenue"].sum().plot.bar()
```Rich directives and cross-references for Jupyter Book and technical publishing.
---
title: Quarterly Sales
jupyter: python3
---
A look at Q4 revenue by region.
```{python}
import pandas as pd
df = pd.read_csv("sales.csv")
```
```{python}
df.groupby("region")["revenue"].sum().plot.bar()
```Multi-language scientific publishing — Python, R, Julia and more via the Quarto system.
{
"cells": [
{
"cell_type": "markdown",
"id": "cell-0001",
"metadata": {},
"source": [
"# Quarterly Sales\n",
"A look at Q4 revenue by region."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cell-0002",
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"df = pd.read_csv(\"sales.csv\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cell-0003",
"metadata": {},
"outputs": [],
"source": [
"df.groupby(\"region\")[\"revenue\"].sum().plot.bar()"
]
}
],
"metadata": {
"jupytext": {
"cell_metadata_filter": "-all",
"notebook_metadata_filter": "-all"
}
},
"nbformat": 4,
"nbformat_minor": 5
}JSON format · contains outputs and metadata, but not well suited to manual edits or version control
A look at Q4 revenue by region.
import pandas as pd
df = pd.read_csv("sales.csv")df.groupby("region")["revenue"].sum().plot.bar()Text notebooks render exactly the same in Jupyter. Outputs are not saved — pair with an .ipynb to keep them.
Open notebooks in VS Code, PyCharm, Vim — any editor, with full language tooling.
Coding agents read and edit the clean text form — so AI can refactor, explain and extend your notebooks.
No outputs, no base64 blobs — just clean diffs your team can actually review in a pull request.
One pre-commit hook — ruff check and ruff format — and every notebook commit meets the same standard as your production code.
Then restart your Jupyter server to activate the extension.
In JupyterLab, use File → New Text Notebook to start fresh with a .py or .md file — or ask your AI assistant to write one.
Right-click any .py, .md, or .qmd file in the JupyterLab file browser and choose Open With → Notebook.
Auto-reload isn't universal. In Jupyter, use File → Reload Notebook from Disk to pick up changes made to the .py file in another editor.
Text notebooks don't store outputs. Pair them with an .ipynb and Jupytext keeps both in sync on every save — commit the text, keep the outputs. The text file always has precedence, and Jupytext raises an error if the .ipynb was modified outside of Jupyter.
In JupyterLab open the .ipynb notebook, then use:
or
And if you opened the text notebook as a notebook, the same menu lets you pair it with an .ipynb. No terminal needed.
Drop a config file at your project root to pair all notebooks at once:
# jupytext.toml formats = "ipynb,py:percent"
or
# jupytext.toml formats = "ipynb,md:myst"
Or add a [tool.jupytext] section to your existing config:
[tool.jupytext] formats = "ipynb,py:percent"
or
[tool.jupytext] formats = "ipynb,md:myst"
Pair a text notebook with an .ipynb and Jupytext keeps both in sync automatically.
Sync happens automatically on save — both files are written together. On load, inputs come from the text file, outputs from the .ipynb.
The Jupytext-Sync extension by Victor Negîrneac syncs both files whenever either one is saved — no terminal needed.
Wire jupytext --sync into a pre-commit hook to keep pairs in sync on every commit.
AI assistants are right at home with scripts and Markdown files. As a text notebook is just that, they read, edit and refactor it as fluently as any other source file — no JSON wrangling, no special tooling.
# %% [markdown] # ### Refactor: vectorize the loop 🤖 - totals = [] - for r in regions: - totals.append(df[df.region==r].sales.sum()) + totals = df.groupby("region").sales.sum()
Jupytext was created by Marc Wouts. Follow Marc on LinkedIn for updates on Jupytext, his other open-source projects, and the occasional random topic.
Jupytext is completely free and open source under the MIT license. What keeps us going is the excitement of learning through interactions with users and experts, and the satisfaction of sharing solutions with the community.
Have a question, a bug report, or an idea? Join us on Discord, or open an issue or start a discussion on GitHub.