A static site generator written in Swift.
Build websites using plain Swift code — no configuration files, no implicit behavior, no magic conventions. Start with a minimal setup that turns Markdown into HTML, then grow it into a structured site as your needs evolve.
Create a new Swift package:
$ mkdir MySite && cd MySite
$ swift package init --type executable
Saga is modular: you pick a reader to parse your content and a renderer to generate HTML. For this guide, we'll use the recommended defaults: Parsley for Markdown and Swim for type-safe HTML.
Add them as dependencies in Package.swift:
// swift-tools-version:5.5
import PackageDescription
let package = Package(
name: "MySite",
platforms: [
.macOS(.v12)
],
dependencies: [
.package(url: "https://github.com/loopwerk/Saga.git", from: "2.0.0"),
.package(url: "https://github.com/loopwerk/SagaParsleyMarkdownReader.git", from: "1.0.0"),
.package(url: "https://github.com/loopwerk/SagaSwimRenderer.git", from: "1.0.0"),
],
targets: [
.executableTarget(
name: "MySite",
dependencies: [
"Saga",
"SagaParsleyMarkdownReader",
"SagaSwimRenderer",
]
),
]
)
Create a content/ folder with a Markdown file:
$ mkdir content
$ echo "# Hello world" > content/index.md
Replace the contents of Sources/MySite/MySite.swift with:
import Saga
import SagaParsleyMarkdownReader
import SagaSwimRenderer
import HTML
func renderPage(context: ItemRenderingContext<EmptyMetadata>) -> Node {
html(lang: "en-US") {
body {
h1 { context.item.title }
Node.raw(context.item.body)
}
}
}
@main
struct Run {
static func main() async throws {
try await Saga(input: "content", output: "deploy")
.register(
readers: [.parsleyMarkdownReader()],
writers: [.itemWriter(swim(renderPage))]
)
.run()
.staticFiles()
}
}
Build your site:
$ swift run
Your site is now in deploy/. Open deploy/index.html in a browser to see it.
For a better workflow, use the built-in dev server with live reload. First install browser-sync:
$ pnpm install -g browser-sync
Then start the development server:
$ swift run watch --watch content --watch Sources --output deploy
This rebuilds your site whenever you change content or code, and automatically refreshes your browser.
Saga avoids hidden behavior entirely.
There are no default values to override, no magic conventions you have to learn, and no configuration files that quietly change how your site is built. Everything is strongly typed, from top to bottom, and you describe exactly how your site is generated using Swift code.
If something happens during a build, you can always point to the code that made it happen.
The quick start shows the simplest case: one type of content, one template. But Saga scales to handle complex sites with multiple content types.
Saga allows you to:
- Add strongly typed metadata to your content
- Define multiple content types with different metadata
- Build archive pages, tag pages, feeds, and indexes
- Swap in different readers and renderers
- Keep everything enforced by the compiler
Saga's metadata system lets you define multiple content types, each with their own strongly typed metadata.
For example, a single site might include:
- Blog articles with tags and publication dates
- A project portfolio with App Store links and screenshots
- Movie reviews with ratings, actors, genres, and release years
Each content type can be indexed, paginated, or grouped independently.
Few static site generators can model diverse content like this while keeping everything type-safe. Saga can.
See the Example project for a complete site with articles, server-side syntax highlighting of code blocks, tags, pagination, an app portfolio, and RSS feeds.
Full documentation covering installation, getting started, metadata modeling, and advanced usage is available:
- In Xcode via Product → Build Documentation
- Online at loopwerk.github.io/Saga/documentation/saga/
Saga is modular. You compose it with readers and renderers that fit your needs.
Markdown readers
- SagaParsleyMarkdownReader — uses Parsley
- SagaInkMarkdownReader — uses Ink and Splash
- SagaPythonMarkdownReader — uses Python-Markdown and Pygments
Renderers
- SagaSwimRenderer — type-safe HTML using Swim
- SagaStencilRenderer — templates using Stencil
Saga requires Swift 5.5+ and runs on macOS 12+ and Linux. The development server requires browser-sync and only works on macOS.
Is your website built with Saga? Send a pull request to add it to the list!
