Setup project directory:

python3 -m venv .venv
echo "pelican[markdown]" > requirements.txt
source .venv/bin/activate
pip install -r requirements.txt

Options for quickstart configuration:

> Where do you want to create your new web site? [.] 
> What will be the title of this web site? Javatronic
> Who will be the author of this web site? Sébastien Lesaint
> What will be the default language of this web site? [fr] en
> What is your URL prefix? (see above example; no trailing slash)
> Do you want to enable article pagination? (Y/n) y
> How many articles per page do you want? [10] 10
> What is your time zone? [Europe/Rome] Europe/Paris
> Do you want to generate a to automate generation and publishing? (Y/n) y
> Do you want to upload your website using FTP? (y/N) n
> Do you want to upload your website using SSH? (y/N) n
> Do you want to upload your website using Dropbox? (y/N) n
> Do you want to upload your website using S3? (y/N) n
> Do you want to upload your website using Rackspace Cloud Files? (y/N) n
> Do you want to upload your website using GitHub Pages? (y/N) y
> Is this your personal page ( (y/N) y

Customize for markdown

Add the following to, which:

  • Markdown support is enabled by installing pelican[markdown]
  • Enable TOC extension to generate Table of Content where [TOC] is present in markdown
  • depth limited to 2
  • Enable Extra extension for Fenced Code Blocks and because the others can't hurt
  • Enable New Line To Break and Sane Lists because they just make sense
  • Enable pymdownx.superfences extension
  • I need it to support code blocks within lists
  'extension_configs': {
    'markdown.extensions.toc': {
      'title': 'Table of contents:',
      'toc_depth': 2
    'markdown.extensions.codehilite': {'css_class': 'highlight'},
    'markdown.extensions.extra': {},
    'markdown.extensions.meta': {},
    'markdown.extensions.sane_lists': {},
    'markdown.extensions.nl2br': {},
    'pymdownx.superfences': {},
  'output_format': 'html5',

Migrating markdown files content

The following content in markdown must be changed.


  • syntax is different
  • some items do not exist in Pelican: layout, image, comments, share, redirect_from
  • category metadata can be dropped as we will use directories instead of metadata
  • description metadata can be renamed to summary
  • content of tags metadata must be converted to a comma-separated list
  • " (quotes) must be removed from title metadata

Table of content

  • syntax is different: {:toc} must be replaced by [TOC]
  • title * Table of Contents can be removed as it is inserted by the markdown plugin

code blocks

  • syntax is different: {% highlight foo} replaced by ```foo and {% endhighlight %} replaced by ```
  • syntax for internal links is different: from [foo]({% posturl bar %}) to [foo]({filename}bar)
    • articles/bar must become /articles/ if current file is not in the articles category (aka. root relative)
    • otherwise, it can become (aka. file relative)
    • for simplicity, we will use root relative everywhere
  • syntax for links to resources is different and resources have a different location
    • {{ site.url }}/resourcs/foo.png must become {static}/images/foo.png
    • (resources could also be "attached" but, so far, I haven't seen the use case, so I'll keep to {static})

Manual migration attempt

  • find all code block types
    grep --no-filename "{% highlight" *.md | xargs -L1 echo | sort | uniq
  • replace opening blocks
    sed -i "s/{% highlight sh %}/\`\`\`shell/g" *.md 
    sed -i "s/{% highlight java %}/\`\`\`java/g" *.md 
    sed -i "s/{% highlight xml %}/\`\`\`xml/g" *.md 
    sed -i "s/{% highlight json %}/\`\`\`json/g" *.md 
  • replace closing blocks
    sed -i "s/{% endhighlight %}/\`\`\`/g" *.md
  • remove heading and trailing --- of Jekyll header
    sed -i "/^\-\-\-/d" *.md

Altering the metadata, including converting data on multiple lines to a single line, is too hard of a challenge to do with bash. The tool is not appropriate. Let's switch to Python.

Python-based migration

See on Github.

Copy Markdown files to the Pelican's location, using a specific subdirectory just for the sake of segregating old migrated posts from new ones, and run the script on them:

mkdir -p content/from_jekyll/articles
cp _posts/articles/*.md content/articles/
mkdir -p content/from_jekyll/tips
cp _posts/tips/*.md content/articles/
git clone ../jekyll_to_pelican_migration
(cd content/articles && ../../../jekyll_to_pelican_migration/ *.md)
(cd content/tips && ../../../jekyll_to_pelican_migration/ *.md)

Copy images files of posts to Pelican's location

cp -r resources/how_to_debug_an_annotation_processor content/images/

If rendering of Markdown files is now ok, remove .md.backup files:

rm content/*/*.md.backup