Outerstellar Outerstellar
← All Projects

fragments4k

A framework-agnostic Markdown-based content engine for Kotlin — drop in .md files, get routing, RSS, sitemaps, full-text search, and pagination out of the box.

fragments4k

A Markdown-based blog and static site library for Kotlin. It reads .md files with YAML front matter from a directory and provides routing, pagination, RSS, sitemaps, and full-text search. Framework adapters exist for HTTP4k, Spring Boot, Javalin, Quarkus, and Micronaut.

View on GitHub

What is fragments4k?

fragments4k is a content management library that runs inside your JVM application rather than as an external process or build tool. Content is parsed at startup from Markdown files on disk. In dev mode, a file watcher picks up changes without restarting the application.

This site uses fragments4k — every page here is a Markdown file rendered by the library.

How does fragments4k work?

Fragments

A fragment is a Markdown file with YAML front matter:

---
title: My First Post
date: 2026-01-15
slug: my-first-post
tags: [kotlin, web]
template: blog
visible: true
preview: A short summary shown in listings.
---

Your Markdown content here.

Front matter fields control routing, visibility, ordering, and template selection. The Markdown body is parsed to HTML and passed to your templates.

Repositories

A FragmentRepository reads fragments from a source (file system, classpath, or custom). Each repository takes a URL builder that maps fragments to routes:

// Blog posts: /blog/2026/01/my-first-post
val blogRepo = FileSystemFragmentRepository("./content/blog") { f ->
    val d = f.date ?: error("Blog posts require a date")
    "/blog/${d.year}/${d.monthValue.toString().padStart(2, '0')}/${f.slug}"
}

// Static pages: /docs/getting-started
val docsRepo = FileSystemFragmentRepository("./content/docs") { f ->
    "/docs/${f.slug}"
}

Engines

Engines sit on top of repositories and handle higher-level operations:

Engine What it does
BlogEngine Paginated listings, tag/category filtering, date archives, prev/next navigation
StaticPageEngine Single-page lookups by slug, ordered page lists
LuceneSearchEngine Full-text indexing and search across one or more repositories

Adapters

Framework adapters wire engines into your web framework's routing and rendering. Each adapter provides routes, view models, and template integration for its target framework.

What features does fragments4k include?

Feature Details
Markdown + YAML Content files with structured front matter
Date-based routing /blog/2026/03/my-post with automatic URL generation
Static pages /page/slug for non-blog content
Pagination Configurable page size, page navigation links
Tag & category filtering Filter listings by any front matter field
RSS feed Atom/RSS feed generation
Sitemap XML sitemap generation
Full-text search Lucene with BM25 ranking
HTMX support Partial rendering for fragment-level updates
Live reload File watcher in dev mode
Coroutines Async content loading

What web frameworks are supported?

Adapter Template Engine Status
HTTP4k JTE / Pebble Stable
Javalin Pebble Stable
Spring Boot Thymeleaf Stable
Quarkus Qute Stable
Micronaut Thymeleaf Stable

Each adapter includes routes for blog, static pages, search, RSS, and sitemap, along with framework-native view models and navigation helpers.

Quick Start

Add the HTTP4k adapter:

<dependency>
    <groupId>io.github.rygel</groupId>
    <artifactId>fragments-http4k</artifactId>
    <version>0.6.2</version>
</dependency>

Create a Markdown file in content/blog/:

---
title: Hello World
date: 2026-01-15
tags: [kotlin, programming]
template: blog
visible: true
---

# Hello World

Content here.

Wire it up:

val repository = FileSystemFragmentRepository("./content/blog") { f ->
    val d = f.date ?: error("Blog post needs a date")
    "/blog/${d.year}/${d.monthValue.toString().padStart(2, '0')}/${f.slug}"
}

val blogEngine = BlogEngine(repository, pageSize = 10)
val searchEngine = LuceneSearchEngine(listOf(repository), null)

val adapter = FragmentsHttp4kAdapter(
    blogEngine = blogEngine,
    renderer = JTETemplates().HotReload("src/main/jte"),
    searchEngine = searchEngine,
    siteTitle = "My Site",
    siteUrl = "https://example.com",
)

val app = adapter.createRoutes()
app.asServer(Jetty(8080)).start()

This gives you blog listings with pagination, tag filtering, RSS, sitemap, and search.

Project Structure

fragments4k/
├── fragments-core/              Domain model, repository, Markdown parser
├── fragments-blog-core/         Blog engine, pagination, archives
├── fragments-static-core/       Static page engine
├── fragments-rss-core/          RSS / Atom feed generation
├── fragments-sitemap-core/      XML sitemap generation
├── fragments-lucene-core/       Lucene full-text search
├── fragments-navigation-core/   Navigation links, archive links
├── fragments-http4k/            HTTP4k adapter (JTE + Pebble)
├── fragments-javalin/           Javalin adapter
├── fragments-spring-boot/       Spring Boot adapter
├── fragments-quarkus/           Quarkus adapter
└── fragments-micronaut/         Micronaut adapter

Modules are independently consumable. If you don't need search, you won't pull in Lucene.

Front Matter Reference

Field Type Required Description
title String Yes Page or post title
slug String Yes URL-safe identifier
date Date Blog only Publication date (YYYY-MM-DD)
template String No Template to render with
visible Boolean No Include in listings (default: true)
tags List No Tags for filtering
categories List No Categories for filtering
order Int No Sort order for static pages
preview String No Summary text for cards and RSS
author String No Post author name

Custom fields are accessible via fragment.frontMatter["key"].

FAQ

What is fragments4k?

fragments4k is a Markdown-based content management library for Kotlin on the JVM. It reads .md files with YAML front matter from a directory and provides routing, pagination, RSS feeds, XML sitemaps, and full-text search via Lucene. It runs inside your application as a library, not as an external process or build tool.

What web frameworks does fragments4k support?

fragments4k has adapters for five JVM web frameworks: HTTP4k, Spring Boot, Javalin, Quarkus, and Micronaut. Each adapter provides framework-native routes, view models, and template integration.

How is fragments4k different from a static site generator?

Static site generators (Hugo, Jekyll, Eleventy) produce HTML files at build time. fragments4k runs inside your JVM application at runtime — content is parsed at startup and served dynamically. This means you get live search, server-side filtering, and hot-reloading without a rebuild step.

Does fragments4k require a database?

No. Content is stored as Markdown files on the filesystem. There is no database dependency. Full-text search is handled by an embedded Lucene index built at startup.

What Java version does fragments4k require?

fragments4k requires JDK 21 or later and Kotlin 2.0+.

License

Apache License 2.0