Question: What is the proper way to specify a custom template path for nbconvert? Under nbonvert version 6, templates are now a directory with several files. Those templates can live in any number of locations depending on the platform. Raspbian: ['/home/pi/.local/share/jupyter/nbconvert/templates', '/usr/local/share/jupyter/nbconvert/templates', '/usr/share/jupyter/nbconvert/templates']  OS X with Pyenv: ['/Users/ac/Library/Jupyter/nbconvert/templates', '/Users/ac/.pyenv/versions/3.8.5/Python.framework/Versions/3.8/share/jupyter/nbconvert/templates', '/usr/local/share/jupyter/nbconvert/templates', '/usr/share/jupyter/nbconvert/templates']  I'm trying to sync my templates over several different platforms and would like to specify a custom location. This post from 2 years ago seems correct, but appears to apply to V5 of nbconvert -- the method has changed names from template_path to template_paths. I've tried the solution suggested in the link above using a template that I know works when placed in one of the known locations. I end up with this error when trying to specify a custom location as suggested: jinja2.exceptions.TemplateNotFound: null.j2 I suspect that by setting the path to /path/to/.jupyter/templates/my_template/, I completely override all the other template locations and lose the null.j2 template that my template extends. I've included my template at the end on the off chance it has some errors that are causing this. The docs for V6 config files are not much help either: TemplateExporter.template_paths : List Default: ['.'] No description  and PythonExporter.template_paths : List Default: ['.'] No description  There's a long thread from May 2019 discussing this on the Git Repo, but I can't quite make sense of what the ultimate conclusion was. My custom Python template: {%- extends 'null.j2' -%} ## set to python3 {%- block header -%} #!/usr/bin/env python3 # coding: utf-8 {% endblock header %} ## remove cell counts entirely {% block in_prompt %} {% if resources.global_content_filter.include_input_prompt -%} {% endif %} {% endblock in_prompt %} ## remove markdown cells entirely {% block markdowncell %} {% endblock markdowncell %} {% block input %} {{ cell.source | ipython2python }} {% endblock input %} ## remove magic statement completely {% block codecell %} {{'' if "get_ipython" in super() else super() }} {% endblock codecell%} 

Answer: Issue #1428 on the Git Repo contains the basis for this solution. From scratch/recent upgrade from v5 to v6 do the following:  Generate a current and up-to-date configuration file for V6 in ~/.jupyter  $ jupyter nbconvert --generate-config   Edit the configuration file ~/.jupyter/jupyter_nbconvert_config.py to add the following lines:  from pathlib import Path # set a custom path for templates in c.TemplateExporter.extra_template_basedirs my_templates = Path('~/my/custom/templates').expanduser().absolute() # add the custom path to the extra_template_basedirs c.TemplateExporter.extra_template_basedirs = [my_templates]   Add templates to the ~/my/custom/templates directory  Each template must be in its own sub directory (/my/custom/templates/foo_template) Each template must contain a conf.json and index.py.j2 file. the index is the actual template. See below for an example   run nbconvert:   $ jupyter nbconvert --to python --template my_custom_template foo.ipynb  conf.json Basic Example { "base_template": "base", "mimetypes": { "text/x-python": true } }  index.py.j2 Example {%- extends 'null.j2' -%} ## set to python3 {%- block header -%} #!/usr/bin/env python3 # coding: utf-8 {% endblock header %} ## remove cell counts entirely {% block in_prompt %} {% if resources.global_content_filter.include_input_prompt -%} {% endif %} {% endblock in_prompt %} ## remove markdown cells entirely {% block markdowncell %} {% endblock markdowncell %} {% block input %} {{ cell.source | ipython2python }} {% endblock input %} ## remove magic statement completely {% block codecell %} {{'' if "get_ipython" in super() else super() }}