Let’s Bring Jupyter Notebooks to Substack
From Jupyter Notebook to Substack post in two clicks
Jupyter Notebooks are my favorite publishing format by far. I write all my posts in them.
They are the perfect medium for math-and-code-heavy technical content: they support LaTeX snippets, code execution, and, to top it all, enable interactive exploration. Every time I’m reading a hands-on tutorial about some fancy new framework, I cannot resist the urge to jump into edit mode and break the code in ways no author can think of.
Unfortunately, if you choose to write in Jupyter Notebooks, you either abandon content distribution by platforms such as Substack, LinkedIn, or X (because they don’t support the format) or manually convert the notebooks to satisfy every possible whim of every possible editor.
So, I built a tool that enables writers to publish Jupyter Notebooks on Substack (and other platforms) with a couple of clicks. It’s called NotebookPress, and it solves four major pain points:
LaTeX rendering,
code snippets,
user interactivity,
and cross-platform compatibility.
Let me give you a tour of the features. In fact, I’m writing this post in NotebookPress, building the Substack-ready post with a single click, then copying the result into the Substack editor with another click. No other modifications needed. You can even check the source Notebook here, play around with the code snippets, build the post you are writing, etc.
This is how the entire editing process looks:
The UI is inspired by VSCode. There’s a simple file explorer on the left, and a workspace on the right. There are two tabs in this example: the Jupyter Notebook source and the HTML result, the one I copied and pasted into the Substack editor, which you are reading now.
(The purple theme is optional. I promise you, there are baseline light and dark themes as well.)
Feature tour
So, about the features. NotebookPress renders LaTeX formulas like
P({\color{blueGray} B} \mid {\color{maizeCrayola} A}) = \frac{P({\color{maizeCrayola} A} \mid {\color{blueGray} B}) P({\color{blueGray} B})}{P({\color{maizeCrayola} A})}, \label{eq:bayes}(with coloring and equation numbering!) into beautiful images like
and you can even reference the equations later in your post: labels like \eqref{eq:bayes} are turned into (1) in your final posts.
Code snippets? Cells like
def square(x):
return x**2
square(42)are executed and rendered into syntax-highlighted images:
If you don’t like the color scheme for the above LaTeX and code renders, it’s all configurable. Font size, font family, syntax highlight theme, background color, and more. Find the palette that matches your style.
Are you creating your illustrations with Python? I got you: NotebookPress includes image outputs as well. Check it out.
(As code execution is done locally in your browser with Pyodide, you can add all supported packages via micropip.)
Here’s the graph of the above-defined square function, made with matplotlib:
I have added the hide-input cell tag to the cell above (check out the source if you don’t believe me), but this is optional. If you want the matplotlib source displayed in your final post, you can show it.
Future roadmap
Currently, NotebookPress is in the beta phase, and I’m still ironing out the major issues. However, I plan to introduce a paid plan soon, with features like
built-in LLM support (with quick LLM prompts for editing, and agents that can see your entire document in their context for more complex tasks),
platform automations (publishing directly to your desired platform),
NotebookPress MCP,
and many more.
If you have any feature requests, bugreports, or any other tech publishing problems you would like me to solve, let me know in the comments or in a DM!







Looks great. Unleash the code!
Can someone do this for R markdown?