Von Directus zu MDX: Meine Website-Evolution

12. September 2025

Eine Reise von komplexer CMS-Architektur zu eleganter Einfachheit - wie ich meine Website von Directus/PostgreSQL auf reines MDX umgestellt habe.

nextjsmdxwebentwicklungarchitektur

Nach monatelanger Entwicklung und ständiger Verkomplizierung meiner persönlichen Website habe ich einen radikalen Schritt gewagt: Komplette Vereinfachung. Hier ist die Geschichte meiner technischen Reise und warum weniger manchmal definitiv mehr ist.

🏗️ Die ursprüngliche Architektur

Meine Website startete als ambitioniertes Full-Stack-Projekt:

Was ich ursprünglich hatte:

  • Backend: PostgreSQL 16 mit Drizzle ORM
  • CMS: Directus für Content-Management
  • Admin-Panel: Selbstgebaute Admin-Oberfläche mit Live-Preview
  • Komponenten-System: Datenbankgesteuerte Komponenten-Registry
  • API-Layer: RESTful Routes für alle Inhalte
  • Authentication: Token-basiertes Admin-System
  • Deployment: Docker Compose mit mehreren Services

Das Problem

Was als "professionelle Lösung" begann, wurde schnell zu einem Wartungsalbtraum:

# Typischer Development-Start
docker compose up -d          # Postgres + Directus starten
npm run drizzle:migrate      # Schema-Migration
npm run components:push      # Komponenten synchronisieren
npm run drizzle:studio       # GUI für Debugging
npm run dev                  # Endlich: Development Server

4-5 Schritte nur um zu entwickeln. Jedes Mal.

🤔 Der Wendepunkt

Der Moment der Wahrheit kam, als ich merkte:

  • 90% meiner Zeit ging für Infrastructure drauf
  • 10% für tatsächlichen Content
  • Ich schrieb mehr Migrations als Blogposts
  • Setup-Zeit > Schreibzeit

Die neue Architektur: Radikal vereinfacht

Current Tech Stack (2025):

// Das ist mein ganzer "CMS":
interface BlogPost {
  title: string;
  date: string;
  excerpt: string;
  tags: string[];
  published: boolean;
}

Mein neuer Stack:

  • Framework: Next.js 15 mit App Router & React 19
  • Content: MDX-Dateien mit Frontmatter
  • Styling: Tailwind CSS 4
  • Deployment: Single Docker Container
  • Database: ❌ Keine!

📝 Content Creation: Vorher vs. Nachher

Vorher (Directus):

  1. Admin-Panel öffnen
  2. "Neuer Post" klicken
  3. Felder ausfüllen
  4. Content in Textarea schreiben
  5. Speichern & Veröffentlichen
  6. Hoffen, dass alles funktioniert

Jetzt (MDX):

---
title: "Mein neuer Post"
date: "2025-01-12"
published: true
---

# Content direkt hier schreiben!

Mit **IntelliSense**, **Syntax-Highlighting** und **Git-Versionierung**.

Ein File. Fertig.

🚀 Die Vorteile des MDX-Ansatzes

1. Developer Experience

# Neuer Blogpost?
touch content/blog/mein-post.mdx
code content/blog/mein-post.mdx

# Deployment?
git push

2. Performance

  • No Database Queries: Alles statisch generiert
  • Fast Builds: Turbopack + keine DB-Abhängigkeiten
  • CDN-Ready: Perfekt für statisches Hosting

3. Flexibilität

# Ich kann direkt React-Komponenten einbauen:

<div className="bg-gradient-to-r from-blue-500 to-purple-600 p-4 rounded">
  Styled Content direkt im Markdown!
</div>

# Oder Mathematik:

$$
E = mc^2
$$

4. Versionierung

Jeder Blogpost hat Git History. Rollbacks, Diffs, Branches - alles da.

🔧 Technical Deep Dive

Blog-System Implementation:

// /src/lib/blog.ts
export function getAllBlogPosts(): BlogPost[] {
  const slugs = getAllBlogSlugs();
  return slugs
    .map((slug) => getBlogPostBySlug(slug))
    .filter((post): post is BlogPost => post !== null)
    .filter((post) => post.published)
    .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
}

26 Zeilen Code ersetzen eine komplette CMS-Database.

Deployment:

# Dockerfile (vereinfacht)
FROM node:20-alpine AS builder
COPY . .
RUN npm ci && npm run build

FROM node:20-alpine AS runner
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/content ./content
CMD ["node", "server.js"]

Ein Container. Ein Command. Es funktioniert einfach.

📊 Vorher vs. Nachher Vergleich

AspektDirectus + DBMDX Static
Setup-Zeit5-10 Minuten30 Sekunden
Dependencies15+ Services0 Services
Build-Zeit3-5 Minuten30-60 Sekunden
DeploymentDocker ComposeSingle Container
BackupDB Dumps + FilesGit Repository
RollbackComplexgit revert
Offline-ArbeitUnmöglichProblemlos

🎯 Lessons Learned

1. Premature Optimization ist real

Ich baute für 1000 Posts, als ich 3 Posts hatte.

2. Developer Experience > Architecture Porn

Elegante Architektur nützt nichts, wenn sie mich vom Schreiben abhält.

3. Static is the new Dynamic

99% meiner "dynamischen" Inhalte waren eigentlich statisch.

4. Git is a CMS

Warum ein CMS bauen, wenn Git schon perfekt ist?

🔮 Zukunftspläne

Was bleibt:

  • MDX für Content
  • Next.js für Framework
  • Tailwind für Styling
  • Simplicity als Grundprinzip

Was kommt:

  • Bessere MDX-Komponenten für interaktive Inhalte
  • Automatisierte Builds bei Git-Push
  • CDN-Integration für globale Performance
  • Vielleicht ein einfaches Admin-Interface (aber nur wenn nötig!)

💡 Fazit: Weniger ist mehr

Diese Migration hat mir gezeigt: Komplexität ist ein Feature, das niemand braucht.

Meine Website ist jetzt:

  • Schneller zu entwickeln
  • 🛡️ Zuverlässiger im Deployment
  • 🔧 Einfacher zu warten
  • 📝 Angenehmer für Content-Creation

Der beste Code ist der, den du nicht schreiben musst.


🤓 Tech-Details für Interessierte

Vollständiger Stack:

{
  "framework": "Next.js 15",
  "runtime": "React 19",
  "language": "TypeScript (strict)",
  "styling": "Tailwind CSS 4",
  "content": "MDX + gray-matter",
  "math": "KaTeX",
  "markdown": "remark-gfm",
  "deployment": "Docker + Coolify",
  "hosting": "Static Generation"
}

Repository-Struktur:

├── content/blog/          # MDX blog posts
├── src/
│   ├── app/              # Next.js app router
│   ├── components/       # React components
│   ├── lib/              # Blog utilities
│   └── styles/           # Global CSS
├── Dockerfile           # Single-container deploy
└── DEPLOY.md            # Simple deployment guide

Weniger Dateien, weniger Komplexität, mehr Focus auf das was wirklich zählt: Content.

Happy Coding! 🚀