diff --git a/pygitweb/main.py b/pygitweb/main.py
index b50b3ef..a90a9ff 100644
--- a/pygitweb/main.py
+++ b/pygitweb/main.py
@@ -6,6 +6,7 @@ Ported from gitweb/gitweb.perl dispatch and action handlers.
 from __future__ import annotations
 
 import os
+from contextlib import asynccontextmanager
 from datetime import UTC, datetime
 from pathlib import Path
 from typing import Annotated
@@ -55,7 +56,7 @@ from pygitweb.tasks import (
 	task_router,
 )
 from pygitweb.templates_env import POSTAMBLE, PREAMBLE, env, jinja_escape
-from pygitweb.timeline_cache import get_all_timeline_events, warm_timeline_cache_async
+from pygitweb.timeline_cache import clear_timeline_cache_async, get_all_timeline_events, warm_timeline_cache_async
 from pygitweb.validation import is_valid_pathname, is_valid_project
 
 try:
@@ -63,6 +64,14 @@ try:
 except ImportError:
 	SubpagePytestHtml = None
 
+
+@asynccontextmanager
+async def timeline_cache_lifespan(app: FastAPI) -> None:
+	warm_timeline_cache_async()
+	yield
+	clear_timeline_cache_async()
+
+
 with open("pygitweb/README.md", encoding="utf-8") as _readme_file:
 	_app_description = _readme_file.read()
 
@@ -72,6 +81,7 @@ app = FastAPI(
 	summary="FastAPI + Pygit2 Repo Browser",
 	description=_app_description,
 	version=__meta__.__version__,
+	lifespan=timeline_cache_lifespan,
 )
 
 SUBPAGES: list[Subpage] = []
@@ -140,11 +150,6 @@ app.include_router(task_router, prefix="/tasks")
 app.include_router(comment_router, prefix="/comments")
 
 
-@app.on_event("startup")
-async def warm_activity_timeline_cache() -> None:
-	warm_timeline_cache_async()
-
-
 @app.middleware("http")
 async def loadavg_middleware(request: Request, call_next):
 	try:
diff --git a/pygitweb/timeline_cache.py b/pygitweb/timeline_cache.py
index 56dfbdb..90fe61f 100644
--- a/pygitweb/timeline_cache.py
+++ b/pygitweb/timeline_cache.py
@@ -220,6 +220,13 @@ def warm_timeline_cache_async() -> bool:
 	return True
 
 
+def clear_timeline_cache_async() -> bool:
+	global PROJECT_TIMELINE_CACHE
+	with _TIMELINE_CACHE_LOCK:
+		PROJECT_TIMELINE_CACHE = {}
+	return True
+
+
 def get_all_timeline_events() -> list[TimelineProjectEvent]:
 	events: list[TimelineProjectEvent] = []
 	with _TIMELINE_CACHE_LOCK:
