Skip to main content
Guides

How to Convert a Jupyter Notebook to a Python Script

By Mithun··7 min read
Quick Answer

Three ways, depending on what you have. 1) `jupyter nbconvert --to script notebook.ipynb` — the official CLI; fast, but it keeps IPython magics like %matplotlib, so the .py won't run in plain Python as-is. 2) An online converter (like our Jupyter → Script tool) — no install, runs in your browser, and strips magics so the output is runnable. 3) A few lines of standard-library Python — a .ipynb is just JSON, so you can pull the code cells yourself. All three drop the saved cell outputs; only the code comes across.

A Jupyter notebook (.ipynb) is great for exploring, but eventually you need a plain .py — to run it as a script, import it as a module, put it in version control, or ship it. The conversion looks trivial, and mostly is, but there are two things that trip people up: IPython magics (%matplotlib inline, !pip install) that aren't valid Python, and the saved outputs baked into the file.

I tested the three common approaches on the same notebook — a markdown cell, imports with a magic, a code cell with saved output, and a function — to show exactly what each one produces. Here's the notebook, as the JSON it really is:

A .ipynb is just JSON

Before converting anything, it helps to know a notebook is a JSON document: a list of cells, each with a cell_type (code or markdown), its source (lines of text), and — for code cells — any saved outputs. That's the whole format. Our test notebook has four cells:

{
"cells": [
{"cell_type": "markdown", "source": ["# Sales analysis\n", "Quick exploration."]},
{"cell_type": "code", "source": ["import pandas as pd\n", "%matplotlib inline"]},
{"cell_type": "code",
"outputs": [{"output_type": "stream", "text": ["rows: 1000\n"]}],
"source": ["df = pd.DataFrame({'x': range(1000)})\n", "print('rows:', len(df))"]},
{"cell_type": "code", "source": ["def total(col):\n", " return col.sum()"]}
],
"nbformat": 4, "nbformat_minor": 5
}
sales.ipynb (trimmed) — the real structure

Method 1 — jupyter nbconvert (the official CLI)

If you have Jupyter installed, the built-in converter is one command:

$ jupyter nbconvert --to script sales.ipynb
# writes sales.py (use --stdout to print instead)
the command

Here's the actual output (nbconvert 7.17.1). It concatenates the code cells — but notice two things:

import pandas as pd
%matplotlib inline
df = pd.DataFrame({'x': range(1000)})
print('rows:', len(df))
def total(col):
return col.sum()
nbconvert output — real

The saved output (rows: 1000) is correctly gone — but %matplotlib inline is still there. nbconvert leaves IPython magics in place, so this .py raises a SyntaxError under plain python (it only runs via IPython). You'll need to strip the magic lines yourself.

Method 2 — an online converter (no install)

If you don't have Jupyter set up, or you want a runnable .py without hand-editing, a browser tool is the quickest path. Our free Jupyter Notebook → Python Script converter runs entirely in your browser: drop in the .ipynb, get a clean .py. It does what nbconvert doesn't — removes the IPython magics and shell escapes — so the result runs as ordinary Python.

Under the hood it's the same idea as Method 3 below (parse the JSON, keep the code) — it just happens client-side, so your notebook never leaves your machine.

Method 3 — a few lines of standard-library Python

Because a notebook is just JSON, you don't strictly need any package. This reads the cells, comments the markdown, drops the magics/shell lines, and skips outputs entirely:

import json
def notebook_to_script(path, keep_markdown=True):
nb = json.load(open(path))
out = []
for cell in nb.get('cells', []):
src = ''.join(cell.get('source', []))
if cell['cell_type'] == 'code':
lines = [ln for ln in src.splitlines()
if not ln.lstrip().startswith(('%', '!'))]
out.append('\n'.join(lines))
elif keep_markdown and cell['cell_type'] == 'markdown':
out.append('\n'.join('# ' + ln for ln in src.splitlines()))
return '\n\n'.join(b for b in out if b.strip()) + '\n'
notebook_to_script.py — stdlib only
# # Sales analysis
# Quick exploration.
import pandas as pd
df = pd.DataFrame({'x': range(1000)})
print('rows:', len(df))
def total(col):
return col.sum()
The .py it produces — real output, valid Python

I verified the result with compile(script, '<nb>', 'exec') — it's valid Python (no leftover magic), the markdown became comments, and the saved rows: 1000 output was dropped. That's the clean, runnable conversion most people actually want.

Which method should you use?

MethodInstall neededMagicsBest for
nbconvert --to scriptJupyterLeft in (may not run)You already run Jupyter
Online converterNone (browser)Stripped → runnableQuick one-off, no setup
Stdlib JSON parseNoneStripped → runnableAutomation / your own pipeline

Whichever you pick, remember what conversion doesn't do: it won't reproduce cell outputs, and code that relied on notebook state (out-of-order execution, In[]/Out[], display side-effects) may behave differently as a top-to-bottom script. Once you have the .py, you can run it in the online Python compiler or tidy it with the Python Formatter.

Convert your notebook — free

Drop an .ipynb in and get a clean, runnable .py — magics stripped, nothing uploaded. In your browser, no signup.

Open the Jupyter → Script tool

Free tools mentioned here

Frequently asked questions

How do I convert a Jupyter notebook to a Python script?

Three common ways: run jupyter nbconvert --to script notebook.ipynb (official CLI, but it leaves IPython magics in the output); use an online converter like pyobfuscate.com's Jupyter → Script tool (no install, strips magics so the .py runs); or, since a .ipynb is just JSON, extract the code cells yourself with a few lines of standard-library Python. All three drop the saved cell outputs.

Does converting a notebook keep the cell outputs?

No. Conversion to a .py script extracts only the code (and optionally markdown as comments). The saved outputs — printed text, tables, plots — are not reproduced; you'd re-run the script to regenerate them. That's usually what you want, since outputs aren't executable code.

Why does my converted .py have %matplotlib or other errors?

IPython magics (%matplotlib, %timeit) and shell escapes (!pip install) are valid in notebooks but not in plain Python, and jupyter nbconvert leaves them in the script — so running it with python raises a SyntaxError. Remove those lines (any line starting with % or !), or use a converter that strips them automatically, like our online Jupyter → Script tool.

Can I convert an .ipynb to .py without installing Jupyter?

Yes. A notebook is a JSON file, so you can parse it and pull out the code cells with the standard-library json module in a few lines — no Jupyter or nbconvert required. Or use an in-browser converter that does it locally without any install; your notebook never gets uploaded.

How do I convert a Python script back into a notebook?

Use jupyter nbconvert or jupytext to go the other direction, or the p2j tool. jupytext in particular can pair a .py and .ipynb and keep them in sync, treating # %% comments as cell boundaries — handy if you want to edit as a script but run as a notebook.

Keep reading