Feni - A simple static site generator with a twist

Feni is a simple static site generator. It takes markdown files and ninja templates and generates HTML. It has a built in local webserver that can be used to preview articles and even make small corrections from the rendered page in the browser.


Feni is a Python package and can be installed using Pip.

    pip3 install feni

Getting started

Create an empty folder somewhere. Change directory into this new empty folder and run the following command.

    feni --sample

This command will generate the a bare minimum file structure for a static site system using Feni. So after running the command, the following files and directories will be present in the directory.

    ├── articles
    │   ├── article2.md
    │   └── article.md
    ├── decorator
    │   ├── css
    │   └── img
    ├── feni.yaml
    └── templates
        ├── article2.html
        ├── article.html
        └── templates.yaml

Feni works as follows. It reads articles from the 'source' folder. From a small segment of yaml at the top of the file, it assigns a type 'X' to that article. Then it looks up in the templates folder for templates that can render articles of the type X. If it finds one Feni converts the markdown file to HTML and inserts it in the template at the place of {{content}} placeholder.

To generate the sample site now, simply run the feni command from the same folder. The a folder 'site' should appear that will contain the whole site


If you look in the generated feni.yaml file it will contain the following lines.

    source: articles
    decorator: decorator
    output: site
    template: templates
  • source key tells Feni the directory from which the markdown articles should be read.
  • 'decorator' key is a folder who's contents will be copied as-such into the output folder. It can be used to hold any style sheets or images that your main content will refer. The contents from this folder will appear in the root of the generated site.
  • 'output' key tells Feni where the generated content should be placed in. This folder will be created if it does not exist already.
  • 'templates' key tells Feni the folder where it should look for templates.


This yaml file inside the templates directory is used to mark the fact that certain templates can render certain types of articles. It's format is as follows.

        - article-type-one
        - article-type-two

Each key is a template file name, and under it, there is the 'types' key. It should be a yaml array that list all the article types this template file can render.

Yaml front matter

This is a small piece of yaml that should be at the top of every article, separated from the markdown content by a line containing only "---". The keys are explained below.

    type: article-type-one
    permalink: post1.html
    publish: true

The type indicates the type of this article. It can be anything. The permalink will be the path of this article in the generated site relative to it's root. The publish is a boolean value that indicate if this article should be included in the generated site.

Using the built in local webserver

From the root folder (where feni.yaml is), run the following command.

    feni --server
    Bottle v0.12.13 server starting up (using WSGIRefServer())...
    Listening on
    Hit Ctrl-C to quit.

Now if you open the printed out url in the browser, it will show you a list of articles. Clicking on any of them will open that article, fully generated, in the browser.

Amending the articles right from the browser

You can make small corrections to the article from the page served by the local webserver. For this, click on any content in the page. The HTML element will be replaced by a textarea with the corresponding content loaded. After you make the changes, press the save button below, and your changes will be applied to the corresponding markdown file.

If you use this feature, make sure you have some kind of backup or version control, which you should be having anyway.

Passing custom data from articles to templates

For example, you might want to pass tags for each articles to the templates so that it will appear in the meta tags section in the generated page. You can use the yaml front matter for this using the data-* keys. For example here is how I pass a "title" for the article that will appear in the "title" tag in the generated template

type: article
data-title: Learning Haskell - Miscellaneous Enlightenments
permalink: haskell/miscellaneous-enlightenments.html
publish: true

and in template...

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">

The data that can be passed is not limited to simple strings, but can be lists or dictionaries and they will be available in the templates as lists or dictionaries, that you can use according to the jinja2 api.

© 2018-08-01 Sandeep.C.R <sandeepcr2@gmail.com>