How to Build a Static Developer Portfolio with a Built-in Markdown Blog in Python

If you’re a developer looking to showcase your projects and share insights, having a portfolio combined with a blog is a powerful tool. In this guide, we’ll walk through building a Python-based static developer portfolio with a built-in Markdown blog, where both projects and posts are stored as files on disk and converted to HTML.

This approach gives you full control over your content, avoids complex CMS setups, and keeps your site lightweight and fast.

Technologies Used

  • Python – for generating the site and rendering content.
  • Markdown – for writing blog posts and project descriptions.
  • HTML & CSS – for templates and styling.
  • Python-Markdown (optional) – for converting Markdown files to HTML.

Step 1: Set Up Your Project

Create a project folder structure:

my_portfolio/
├─ posts/         # Markdown blog posts
├─ projects/      # Markdown project descriptions
├─ templates/     # HTML templates
├─ static/        # CSS and images
├─ generate.py    # Python generator script

Install the Python-Markdown library:

pip install markdown

Step 2: Write Markdown Content

Inside the posts folder, create files like first_post.md:

# My First Blog Post

This is an example of a Markdown post. It will be converted to HTML automatically.

Similarly, add project descriptions in projects/project1.md:

# My Cool Project

A short description of my project, its features, and technologies used.

Step 3: Create HTML Templates

Inside the templates folder, create base.html:

<!DOCTYPE html>
<html>
<head>
    <title>{{ title }}</title>
    <link rel="stylesheet" href="../static/style.css">
</head>
<body>
    <header>
        <h1>{{ title }}</h1>
        <nav>
            <a href="index.html">Home</a> |
            <a href="blog.html">Blog</a> |
            <a href="projects.html">Projects</a>
        </nav>
    </header>
    <main>
        {{ content }}
    </main>
</body>
</html>

Step 4: Write the Python Generator

Create generate.py to convert Markdown to HTML:

import os
import markdown

TEMPLATES_DIR = 'templates'
POSTS_DIR = 'posts'
PROJECTS_DIR = 'projects'
OUTPUT_DIR = 'site'

os.makedirs(OUTPUT_DIR, exist_ok=True)

def render_template(template_path, context):
    with open(template_path, 'r', encoding='utf-8') as f:
        template = f.read()
    for key, value in context.items():
        template = template.replace(f'{{{{ {key} }}}}', value)
    return template

def build_blog():
    posts_html = ""
    for filename in os.listdir(POSTS_DIR):
        if filename.endswith('.md'):
            filepath = os.path.join(POSTS_DIR, filename)
            with open(filepath, 'r', encoding='utf-8') as f:
                html_content = markdown.markdown(f.read())
                posts_html += f"<article><h2>{filename.replace('.md','')}</h2>{html_content}</article><hr>"
    html = render_template(os.path.join(TEMPLATES_DIR, 'base.html'), {'title': 'Blog', 'content': posts_html})
    with open(os.path.join(OUTPUT_DIR, 'blog.html'), 'w', encoding='utf-8') as f:
        f.write(html)

def build_projects():
    projects_html = ""
    for filename in os.listdir(PROJECTS_DIR):
        if filename.endswith('.md'):
            filepath = os.path.join(PROJECTS_DIR, filename)
            with open(filepath, 'r', encoding='utf-8') as f:
                html_content = markdown.markdown(f.read())
                projects_html += f"<div class='project'><h2>{filename.replace('.md','')}</h2>{html_content}</div><hr>"
    html = render_template(os.path.join(TEMPLATES_DIR, 'base.html'), {'title': 'Projects', 'content': projects_html})
    with open(os.path.join(OUTPUT_DIR, 'projects.html'), 'w', encoding='utf-8') as f:
        f.write(html)

def build_index():
    content = "<p>Welcome to my developer portfolio!</p>"
    html = render_template(os.path.join(TEMPLATES_DIR, 'base.html'), {'title': 'Home', 'content': content})
    with open(os.path.join(OUTPUT_DIR, 'index.html'), 'w', encoding='utf-8') as f:
        f.write(html)

if __name__ == "__main__":
    build_index()
    build_blog()
    build_projects()
    print("Site generated in ./site")

Step 5: Add Styling

Create static/style.css:

body {
    font-family: Arial, sans-serif;
    max-width: 900px;
    margin: auto;
    padding: 20px;
    line-height: 1.6;
}

header {
    text-align: center;
    margin-bottom: 40px;
}

nav a {
    margin: 0 10px;
    text-decoration: none;
    color: #333;
}

Step 6: Generate Your Site

Run the generator:

python generate.py

All your pages will appear in the site folder as static HTML files, ready to be deployed.

Step 7: Next Steps

  • Add metadata to Markdown files (author, date, tags).
  • Generate individual pages per blog post.
  • Add search or categories for better organization.
  • Deploy the site on GitHub Pages, Netlify, or Vercel.

Conclusion

With just Python, Markdown, and a bit of HTML/CSS, you can create a full-featured static developer portfolio with a built-in blog. It’s easy to maintain, fast to load, and gives you total control over your content.

Leave a Reply