Post

Migrating from WordPress to Quarkus Roq

3 tags

A practical look at what it took to move this site from WordPress to Quarkus Roq, from SQL dump to aliases, feeds, and tag pages.

I recently migrated this blog from WordPress to Quarkus Roq. The move was not driven by hype or novelty. It was driven by the fact that WordPress is a very large and complex system for what I actually need here: a handful of static pages and a blog.

For someone running a content-heavy, multi-user publishing platform, WordPress still makes sense. But for my use case it had become too much surface area to maintain, too much software to secure, and too much machinery around a site that is mostly text.

Roq felt like a better fit for three simple reasons:

  1. I am already familiar with the Quarkus ecosystem.
  2. Markdown files are much easier to integrate with my local brain and personal wiki.
  3. A static site is significantly simpler to maintain than a full WordPress installation.

The migration itself ended up happening in two phases. The first phase was about moving content. The second was about turning that converted content into a site that actually behaved like a finished website.

I should also mention that I did not go into this completely blind. I got a lot of useful tips and confidence from reading Zineb Bendhiba's post, From Jekyll to Quarkus Roq: Migrating My Blog as a Java Dev. Her write-up is about a different starting point, but it helped confirm a few practical things ahead of time: Roq is a viable home for an existing blog, preserving old URLs matters, and it is worth thinking early about how much of the default theme you want to keep versus how much you want to own yourself.

The first requirement: a WordPress database dump

One important precondition did not show up clearly in the migration logs, but it should have: before doing anything else, you need a dump of the WordPress database.

That dump was the real source of truth for the migration. It was needed to extract:

  • published posts
  • publication dates
  • tags and categories
  • original slugs
  • old permalink structure
  • references to media hosted under wp-content/uploads

Without that SQL dump, this migration would have been guesswork.

Phase 1: converting content

The first pass was relatively mechanical, but still not trivial.

Posts were extracted from the WordPress data, converted into Markdown, and written into Roq's content structure:

content/posts/YYYY-MM-DD-slug/index.md

That part also required preserving metadata such as title, publication date, tags, and descriptions. In practice, this was the point where the site stopped being "a WordPress database" and started becoming a normal tree of files that can be edited with standard tools.

This change alone is one of the biggest benefits of the migration for me. Once the posts are just Markdown files in a repository, they become much easier to search, link, edit, back up, refactor, and reuse.

There was one content-level detail that also needed attention: code snippets.

In Roq, depending on what you are writing, some snippets need escaping so they are rendered as intended instead of being interpreted along the way. I had a few posts using Maven-style property expressions, and those needed to be adjusted to $\{camel.version}.

This is a small detail, but it is exactly the kind of thing that shows why a migration still needs careful review even after the bulk conversion appears to be done.

Media is part of the migration too

Moving the post bodies was only part of the job. A lot of content also depended on images and files previously hosted by WordPress under https://www.orpiske.net/wp-content/uploads/.

That meant the migration also had to:

  • identify media referenced by posts
  • download the files that were still available
  • rewrite links to local paths in the Roq content tree
  • record anything missing for manual follow-up

This is easy to underestimate. If you only migrate the text and forget the assets, the result looks successful in the repository but broken in the browser.

Phase 2: making it into a real site

The second phase was more interesting than I expected. Content conversion was not enough. Once the posts were in place, other issues became obvious.

The main follow-up work was:

  1. build a custom theme direction
  2. improve readability with real content on screen
  3. make deployment work correctly under a subpath
  4. add RSS and feed endpoints
  5. preserve old WordPress permalinks
  6. restore working tag pages

Theme and readability

I wanted the result to be minimal, clean, and modern, while still keeping things simple and standards-friendly.

That led to a typography-first layout with a single-column reading flow, semantic HTML, and restrained styling. Once real articles were rendered, a few problems were immediately visible: inline links were too subtle, body text was too light, and title hierarchy was weaker than it should have been. Those are the kinds of things you only really notice after the migration data hits the page.

Deployment testing under a subpath

One practical issue was testing the site under:

https://orpiske.net/new-website/

That was not meant to be the final public path. It was a temporary server-side test to make sure the site would still look correct once deployed.

Even as a test, it exposed the usual static-site gotcha: if your paths assume the site is hosted at the domain root, things look broken very quickly. CSS, navigation, and generated URLs all need to agree with the real deployment path you are validating against.

Feeds and tags

RSS and feed support had to be wired in explicitly, and tags needed extra work too. In the logs, one of the more useful lessons was that something can be technically generated and still not be properly integrated. A feed file that exists but is not linked is still effectively missing.

The same thing happened with tags. Tag links existed, but the proper tagging support was not fully enabled at first, and once it was enabled the resulting pages did not visually match the rest of the site. That was solved pragmatically instead of trying to force a perfect deep override immediately.

Preserving old WordPress URLs

This was non-negotiable.

An established blog accumulates links over time, and a migration that breaks them is not finished. The WordPress dump made it possible to map old permalinks to the new Roq structure and add aliases so legacy URLs could keep working.

This was not perfectly mechanical in every case. Some posts needed judgment because dates or titles had drifted over time. That is another good reminder that migrations are rarely as clean as a one-shot export/import story suggests.

Why this fits me better

After going through the process, I am even more convinced this was the right move.

With Roq, the site is closer to the way I actually work:

  • content is plain text
  • changes live in Git
  • the tooling is already familiar
  • the generated result is static
  • maintenance is much smaller in scope

Most importantly, I no longer need to operate a full CMS just to publish notes, articles, and a few fixed pages. For my needs, that is a much better trade-off.

Final thought

The migration from WordPress to Quarkus Roq was not just a content export. It was a reduction in complexity.

The database dump made the move possible, Markdown made the content manageable again, and the second migration pass made the result usable as an actual website.

If your site is mostly content and you are already comfortable in the Quarkus ecosystem, Roq is a very compelling alternative.