A Search-Engine Friendly Portfolio
Updated: 19 Apr 2026
As a developer, your portfolio is your digital handshake. It needs to be fast, secure, and accessible, but perhaps most importantly, it needs to be found. While many developers focus solely on the visual design or the tech stack, the underlying architecture plays a critical role in how search engines like Google crawl and index your work.
In this post, we’ll dissect the SEO implementation of a Django-based portfolio (specifically erikwalther.eu), looking at how URL structures, dynamic sitemaps, semantic HTML, and structured data work together to maximize visibility.
1. Clean, Semantic URL Structures
Search engines favor URLs that are human-readable and logically structured. A messy URL with random IDs or query parameters is a red flag for both crawlers and users.
In this project, the URL configuration (portfolio/urls.py) demonstrates a clean hierarchy:
urlpatterns = [
path('', views.project_list, name='project_list'),
path('project/<slug:project_slug>/', views.project_detail, name='project_detail'),
path('project/<slug:project_slug>/<slug:page_slug>/', views.project_page, name='project_page'),
]
By using slugs (URL-friendly versions of titles) instead of primary keys (e.g., /project/42/ vs /project/my-awesome-django-app/), the site provides immediate context to search engines. The hierarchical structure (/project/{slug}/{page_slug}/) clearly indicates that a specific page belongs to a specific project, helping crawlers understand the relationship between content pieces.
Furthermore, the Project model in models.py automatically generates these slugs upon saving:
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)
This automation ensures consistency across the site, preventing duplicate content issues caused by manual URL errors.
2. Dynamic, Granular Sitemaps
A static sitemap.xml file quickly becomes obsolete the moment new content is added. This portfolio solves that by generating the sitemap dynamically via Django’s sitemap framework (views.py).
The implementation goes beyond a single list. It breaks the sitemap into three distinct classes:
StaticSitemap: For the homepage and core navigation.
ProjectSitemap: For individual project overview pages.
ProjectPageSitemap: For detailed sub-pages within projects.
class ProjectPageSitemap(Sitemap):
changefreq = 'monthly'
priority = 0.7
def items(self):
return ProjectPage.objects.select_related('project')
This granularity is crucial. By assigning different changefreq and priority values, the site signals to search engines which parts of the site are likely to change frequently (like the homepage or active projects) versus those that are more static (archived project details).
Additionally, the robots.txt view dynamically constructs the sitemap URL based on the current request:
def robots_txt(request):
sitemap_url = request.build_absolute_uri('/sitemap.xml')
# ...
f"Sitemap: {sitemap_url}",
This ensures that regardless of whether the site is hosted on a staging server, a local environment, or production, the robots file always points to the correct location.
3. Semantic HTML and Accessibility
SEO and accessibility are two sides of the same coin. Google’s algorithms increasingly reward sites that are accessible to screen readers and assistive technologies because they are easier for bots to parse.
The base.html template utilizes proper semantic tags:
<header> and <footer> for structural context.
<main id="main-content"> to define the primary content area, allowing crawlers to skip repetitive navigation.
<article> tags for individual projects and blog posts.
aria-label attributes on navigation links (e.g., "Skip to main content").
The breadcrumb navigation in project_page.html is another excellent example:
<nav class="breadcrumb" aria-label="Breadcrumb">
<a href="/">Home</a> › <a href="...">Project Title</a> › <span aria-current="page">Page Title</span>
</nav>
This not only helps users navigate but also provides search engines with a clear hierarchy of the page's location within the site structure.
4. Rich Structured Data (Schema.org)
Perhaps the most powerful SEO tool in this stack is the extensive use of JSON-LD structured data. This allows the site to speak the "language" of search engines directly, enabling rich snippets in search results.
The templates inject context-aware Schema.org data:
Homepage: Defined as a WebSite with copyright and license info.
Project List: Defined as a CollectionPage containing an ItemList.
Project Detail: Defined as SoftwareSourceCode, highlighting the programming language (Python), repository links, and creation dates.
Project Pages: Defined as CreativeWork.
For example, in project_detail.html:
{
"@context": "https://schema.org",
"@type": "SoftwareSourceCode",
"name": "My Project",
"programmingLanguage": "Python",
"codeRepository": "https://github.com/...",
"targetProduct": {
"@type": "WebApplication",
"url": "https://live-demo.com"
}
}
This tells Google exactly what the content is: a piece of software. This increases the likelihood of the project appearing in specialized search results for developers or software tools, rather than just generic text results.
Conclusion
The SEO strategy for this portfolio isn't an afterthought; it's woven into the fabric of the application. By combining clean URL structures, dynamic sitemaps, semantic HTML, and granular structured data, the site creates a robust foundation for organic growth.
For developers building portfolios, the lesson is clear: Don't just build for humans. Build for the machines that help humans find you. A well-architected backend is just as important as a polished frontend when it comes to being discovered.