Blazing-Fast Blogs with Laravel, Markdown, and Sushi
When it comes to building a personal blog, the Laravel community offers a wide range of tools that make the process a breeze. Projects like Jigsaw and Statamic provide powerful static site generation, with Statamic doubling as a flexible CMS complete with media management. Alternatively, you could build something more scalable and customisable using tools like Filament.
But sometimes, all you need is a simple and fast solution. A full-featured CMS can be overkill when all you want to do is publish articles. For my site, I opted to build a custom blog that is elegant, lightweight, and efficient.
Markdown Rendering in Laravel
Reading content from Markdown and rendering it in Blade views comes with many benefits. Laravel’s built-in helper Str::markdown($content)
makes it easy to convert Markdown into HTML.
To enhance this, I’m using the Phiki CommonMark extension for theming code blocks:
\Illuminate\Support\Str::markdown($article->content, extensions: [
new \Phiki\CommonMark\PhikiExtension('github-dark'),
])
Using YAML Front Matter
While Markdown handles body content, blogs typically need more metadata: titles, slugs, publish dates, tags, excerpts, and so on.
That’s where Spatie’s https://github.com/spatie/yaml-front-matter package comes in. It allows you to define structured metadata at the top of your Markdown files:
---
title: "Introducing Markdown"
author: 'Steven Richardson'
date: "June 20th, 2025"
excerpt: "A small description for list pages and RSS feeds"
tags: [Laravel, Personal]
---
This makes it easy to extract data alongside your content body.
ArticleRepository: Reading from the Filesystem
Using Laravel’s File facade and Spatie’s front matter package, I created an ArticleRepository to scan Markdown files, extract content and metadata, and return them as structured data.
public function all()
{
return collect(File::files($this->directory))
->filter(fn ($file) => $file->getExtension() === 'md')
->map(function ($file) {
$document = YamlFrontMatter::parse(File::get($file->getPathname()));
return [
'title' => $document->matter('title'),
'slug' => basename($file->getFilename(), '.md'),
'excerpt' => $document->matter('excerpt'),
'date' => $document->matter('date'),
'content' => $document->body(),
];
})
->filter(fn ($item) => ! empty($item['date']))
->sortByDesc(fn ($item) => Carbon::parse($item['date']))
->values();
}
This repository can:
- List all published articles (
all()
) - Find an article by slug (
find($slug)
)
It works well, but pagination is where it gets tricky — which brings us to Sushi.
Eloquent-Like Power with Sushi
Laravel’s pagination is tightly coupled with Eloquent, unless you want to roll your own with the LengthAwarePaginator
, but that is quite a bit of work. But what if you don’t have the time to build and maintain your own?
This is where Sushi by Caleb Porzio shines — a package that lets you feed arrays into Eloquent models as if they were database rows.
Here’s a simplified Article model using Sushi:
class Article extends Model
{
use Sushi;
public function getRows()
{
return (new ArticleRepository)->all()->toArray();
}
}
Now you can use Eloquent features like pagination and firstOrFail():
$articles = Article::paginate(12);
$article = Article::where('slug', $slug)->firstOrFail();
Conclusion
This setup gives you a blazing-fast, database-free blog with full Eloquent capabilities. By combining Laravel’s filesystem tools, Spatie’s YAML package, and Sushi, you can build a content hub that’s elegant and high-performance — without introducing unnecessary complexity.
If your blog grows in size or feature scope, migrating to a database-backed CMS is always an option. But for a small, focused personal site, this stack offers the perfect balance of speed, simplicity, and flexibility.
