Creating and managing a static website with Nikola
In this guide, you will learn how to create and manage a static website using the Nikola static website generator.
What is a static website?
A static website is a collection of pre-built HTML, CSS, and JavaScript files that are delivered to visitors exactly as they are stored. Every visitor sees the same content, and nothing changes unless you manually update the files.
Installing uv
uv is a fast Python package and project manager. It handles installing Python tools and their dependencies quickly and reliably. We'll use it to install Nikola.
macOS / Linux:
curl -LsSf https://astral.sh/uv/install.sh | sh
Windows (PowerShell):
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
Windows (WinGet):
winget install astral-sh.uv
Via your package manager (Linux):
On most Linux distributions you can install uv through your system package manager.
Check the uv installation docs for instructions specific to your distribution.
Installing Nikola
Once uv is installed, you can install Nikola with a single command:
uv tool install "nikola[extras]"
We install the extras to enable Markdown support and ensure Nikola includes the most commonly used features by default.
To verify the installation was successful, run:
nikola version
You should see the installed version number printed in your terminal.
Creating your first site
To create a new Nikola site, run:
nikola init my-site
Nikola will ask you a few setup questions. Your site name, description, and preferred language. When it asks whether to enable pretty URLs, type y and hit Enter.
Pretty URLs turn addresses like yoursite/blog/my-post.html into yoursite/blog/my-post.
Nikola does this by placing each page in its own folder with an index.html file inside, so the URL looks like a clean path rather than a file. It's much easier to enable this at setup than to change it later.
Once done, navigate into your new site folder:
cd my-site
Editing your configuration
When you initialize a Nikola site, it generates a conf.py file in your site's root folder. This is where you control almost everything about how your site behaves. Here's what I recommend changing:
Posts and pages
POSTS = (
("posts/*.md", "blog", "post.tmpl"),
("posts/*.rst", "blog", "post.tmpl"),
("posts/*.txt", "blog", "post.tmpl"),
("posts/*.html", "blog", "post.tmpl"),
)
PAGES = (
("pages/*.md", "", "page.tmpl"),
("pages/*.rst", "", "page.tmpl"),
("pages/*.txt", "", "page.tmpl"),
("pages/*.html", "", "page.tmpl"),
("pages/*.php", "", "page.tmpl"),
)
POSTS tells Nikola where to find your blog posts and how to render them. Each line maps a file pattern to an output folder and a template. Here we're telling Nikola to look for posts written in Markdown, reStructuredText, plain text, or HTML. All posts are stored in the posts/ folder and published to the blog/ folder using the post.tmpl template.
PAGES works the same way but for standalone pages. Notice that the output folder is left empty (""), meaning pages are published to the root of your site rather than a subfolder. We've also added .php support here in case you have any PHP-based pages you want Nikola to manage.
Hide Source Links
SHOW_SOURCELINK = False COPY_SOURCES = False
By default, Nikola adds a link at the bottom of each post pointing to the raw source file. Most people don't want this on a public-facing site, so we turn it off. SHOW_SOURCELINK hides the link from the page, and COPY_SOURCES stops Nikola from copying the raw source files into your output folder at all.
Blog Index Path
INDEX_PATH = "blog"
This sets the URL path where your blog post index (the list of all your posts) will be published. With this setting, your blog listing will live at yoursite/blog instead of the root of your site. This is useful if you want your homepage to be a custom page rather than a list of posts.
Disabling the blog index
If you're not using Nikola as a blog and just want a regular static website, you can disable the blog index and its feeds entirely. Find the following lines in your conf.py and remove the # at the start of each, and change False to True:
DISABLE_INDEXES = True DISABLE_MAIN_ATOM_FEED = True DISABLE_MAIN_RSS_FEED = True
DISABLE_INDEXES removes the blog index page completely, while DISABLE_MAIN_ATOM_FEED and DISABLE_MAIN_RSS_FEED disable the automatically generated Atom and RSS feeds. These are only useful if you're publishing a blog that readers can subscribe to, so there's no reason to generate them for a plain website.
Teasers on the index
INDEX_TEASERS = True
When this is enabled, your blog index page will show only a preview of each post rather than the full content. To mark where the preview cuts off, add the following comment in your post at the point you want to truncate:
<!-- TEASER_END -->
Everything above that line will appear on the index page, with a "Read more" link to the full post.
Date format
DATE_FORMAT = 'MMMM d, yyyy'
This controls how dates are displayed on your posts. MMMM outputs the full month name, d the day, and yyyy the four-digit year.
Heading levels
By default, Nikola demotes all headings in your content by one level, so an h1 becomes an h2, an h2 becomes an h3, and so on. The idea is that your post title already occupies the h1 on the page, so your content headings should start at h2.
To disable this, find the DEMOTE_HEADERS line in your conf.py, remove the # at the start, and set it to 0:
DEMOTE_HEADERS = 0
Creating a new page
To create a new page, run:
nikola new_page
Nikola will prompt you for a title and create a new file in the pages/ folder. Open that file in your text editor and write your content in Markdown. When you're done, rebuild the site with nikola build to see your changes.
Creating a new post
To create a new blog post, run:
nikola new_post
Nikola will prompt you for a title and create a new file in the posts/ folder. Open that file in your text editor and write your content in Markdown. When you're done, rebuild the site with nikola build to see your changes.
Using a custom template for heading levels, accessibility, and heading links
Download templates.zip, which includes a modified version of the bootblog4 theme's templates with the following improvements:
- Post titles on the index page render as
<h2>headings instead of<h1> -
aria-current="page"is added to the active navigation link for better accessibility - Links are removed from page and post headings
Extract the zip and copy the templates/ folder to your site's root directory. Nikola will automatically use your templates instead of the theme's defaults.
Managing files and scripts
Nikola has a special files/ directory in your site's root folder. Anything you place inside it gets copied directly into your output when you run nikola build, with the folder structure preserved exactly as-is.
For example, if you have files specific to a certain page, you can mirror that page's folder structure inside files/.
To reference a file from within the same page, use a relative path.
If you need to reference a file from anywhere else on the site, use an absolute path starting with / to resolve from the root of your site.
Building and previewing your site
To build your site, run:
nikola build
To preview it locally in your browser, run:
nikola serve --browser
This will open your site at http://localhost:8000 so you can see it before publishing.
Deploying your site
Nikola can be deployed in many ways, including GitHub Pages, rsync, and rclone, allowing you to choose the workflow that best fits your hosting environment.
Conclusion
I hope this guide was able to help you create and manage a static site with Nikola. If you need any help or have questions, you can contact me using the information found on my contact page.
If you'd like to learn more about Nikola, you can read the handbook.