Back to Blog
nuxtcmsopinioncase-study

I Tried 4 CMSes Before Landing on Nuxt Studio

Framer, Sanity, Directus, and a lot of frustration. Here's why my portfolio content now lives in Git files and costs me $0/month to manage.

ยท 9 min read
Migration path from Framer to Sanity to Directus to Nuxt, showing each CMS crossed out with price labels and Nuxt glowing green at $0
On this page

$15/month. That's what Framer was charging me to host a portfolio site that gets a few hundred visits a month. Not a SaaS app. Not an e-commerce store. A portfolio. A glorified list of projects and a blog.

I've since tried Sanity, self-hosted Directus, and finally landed on Nuxt Content v3 with Nuxt Studio. My CMS bill is now $0. My content lives in Git. And I can move the whole thing to a different host in about 20 minutes.

Here's how I got here, and why I'm not moving again.

The Framer Exit

Let me be clear: Framer is a beautiful tool. The editor is smooth, the templates are gorgeous, and the animations are chef's kiss. If you're a designer who wants a portfolio up in an afternoon, it's genuinely great.

But I'm a developer. And $15/month for a static portfolio started feeling like a subscription to a gym I wasn't using properly.

The problems weren't just the price:

  • No real code ownership. Your site lives in Framer's editor. Export options are limited. If Framer doubles their pricing tomorrow, you're stuck.
  • Custom functionality? Good luck. Want a custom RSS feed? A dynamic sitemap? Code highlighting in blog posts? You're fighting the platform instead of building.
  • Performance. Framer sites are fast-ish, but you're loading their runtime whether you need it or not.

I liked Framer for what it was. But for what I needed, it was the wrong tool at the wrong price.

Sanity: Great Until the Bill Arrives

After Framer, I went the "proper" headless CMS route. Sanity has a generous free tier, a fantastic query language (GROQ), and a studio that's genuinely nice to work with.

For about three months, I was happy. Then I started paying attention to the pricing page.

Sanity's free tier works fine for a solo portfolio. But the moment you start thinking bigger, the numbers get uncomfortable. API CDN requests, dataset storage, bandwidth. It all adds up. And the real cost isn't even monetary. It's architectural.

Your content lives in Sanity's cloud. Your schemas are defined in their format. Your queries use GROQ, which is Sanity-only. Every piece of content you create deepens the lock-in.

When I wanted to migrate my blog posts out, I had to write a custom export script, transform the block content format back into markdown, and manually fix all the image references. For a portfolio blog with maybe 10 posts, it took me an entire evening. Imagine doing that with 200 posts.

Directus: Self-Hosting Your Way Into More Problems

"I'll self-host my CMS," I said, already running 30+ Docker containers on my Contabo VPS. "What's one more?" ๐Ÿ˜…

Directus is genuinely good open-source software. It gives you a beautiful admin panel, auto-generates REST and GraphQL APIs from your database, and lets you own everything. On paper, it was perfect.

In practice? Three problems.

1. Another container on an already packed VPS. Directus needs PostgreSQL (or MySQL), plus its own Node.js process. My VPS was already running at ~80% RAM. Adding Directus meant something else had to shrink, or I'd need a bigger server. More money, more complexity.

2. Maintenance never stops. Self-hosting a CMS means self-hosting its database, its migrations, its updates. When Directus pushes a major version, you're the one debugging why the upgrade script failed at 11pm on a Tuesday.

3. The lock-in problem, again. Your content is in a PostgreSQL database, structured however Directus schemas define it. Want to move to a different CMS? Cool, write another migration script. Convert all your relational data back into flat files. Re-map your media. Again.

I was solving the pricing problem by self-hosting, but I wasn't solving the lock-in problem at all. I just moved the lock from a SaaS company's servers to a database on my own server.

The Realization

Every CMS I tried had the same fundamental issue: my content didn't belong to me in any portable way.

Framer owned the rendering. Sanity owned the storage format. Directus owned the database schema. Moving between any of them meant a migration project.

Then I looked at my content and asked a simple question: what is a portfolio, really?

It's a list of projects (titles, descriptions, tags, links). A few testimonials. Some service descriptions. Blog posts. An about section. That's it. It's just data. Simple, flat, structured data.

Why was I running a database for this?

Nuxt Content v3: Files Are the CMS

Nuxt Content v3 treats your file system as the content layer. Blog posts are Markdown files. Portfolio data (projects, testimonials, services) are YAML files. Everything lives in your Git repo, versioned alongside your code.

Here's what my content directory looks like:

content/
โ”œโ”€โ”€ blog/
โ”‚   โ”œโ”€โ”€ hello-world.md
โ”‚   โ””โ”€โ”€ self-hosting-30-docker-containers.md
โ”œโ”€โ”€ projects/
โ”‚   โ”œโ”€โ”€ kora-payments.yml
โ”‚   โ””โ”€โ”€ fincra-dashboard.yml
โ”œโ”€โ”€ testimonials/
โ”‚   โ”œโ”€โ”€ john-doe.yml
โ”‚   โ””โ”€โ”€ jane-smith.yml
โ”œโ”€โ”€ services/
โ”‚   โ””โ”€โ”€ web-development.yml
โ””โ”€โ”€ data/
    โ””โ”€โ”€ site.yml

No database. No API keys. No hosted backend. You define your schemas in content.config.ts with Zod, and Nuxt Content handles querying, rendering, and hot-reloading in dev.

The migration from Directus? I exported my data, saved each item as a YAML file, and committed to Git. Took about an hour, including writing the schemas.

Where Nuxt Studio Fits In

"But Sherif, do you really want to write YAML by hand every time you update a project?"

No. That's where Nuxt Studio comes in.

Nuxt Studio is a visual editor that sits on top of your Nuxt Content project. It connects to your Git repo and gives you a nice UI to edit content, preview changes live, and commit when you're happy.

It's not a CMS in the traditional sense. There's no database and no separate hosted platform. It's a Nuxt module that runs as part of your app, with a built-in editor route you can lock down with GitHub, GitLab, or even Google OAuth. That last one is interesting - it means you can hand content editing to someone who doesn't have a GitHub account. When you save, it commits directly to your Git repo. That's it.

For blog posts, I still prefer VS Code. But for updating a project description, adding a testimonial, or fixing a typo? Studio is perfect. Open the browser, make the change, save, done. No terminal required.

Nuxt Studio editor showing visual content editing with live preview
Nuxt Studio editor showing visual content editing with live preview

The Numbers ๐Ÿ’ฐ

FramerSanityDirectus (self-hosted)Nuxt + Cloudflare
Monthly cost$15$0-99~$5 (VPS share)$0
Content portabilityLowMediumMediumHigh (it's files)
Vendor lock-inHighHighMediumNone
Custom functionalityLimitedGoodGoodFull (it's Nuxt)
Migration effortHighMediumMediumCopy the files
MaintenanceNoneLowHighNone

My portfolio now runs on Cloudflare Pages. Free tier. My domain is already on Cloudflare, so deployment is git push and done. Build time is under a minute.

The Trade-Offs

No visual page builder. Nuxt Studio lets you edit content, not drag-and-drop layouts. If you want Framer-style design flexibility without code, this isn't it.

You need to know Nuxt. This stack assumes you can build a Nuxt app. If you're a designer who just wants a portfolio online, Framer is still the better choice for you.

Content v3 is still maturing. I've hit quirks with data collections (each item needs its own file, no arrays in single files). The docs are improving but there are gaps. You'll spend some time in GitHub issues.

Studio isn't as polished as Sanity's studio. Sanity's editing experience is genuinely best-in-class. Nuxt Studio is good and getting better, but it's not there yet.

You're still the ops team. No database to maintain, sure. But you still need to handle build configs, deployment, and debugging when the Nuxt build fails because of a malformed frontmatter field at midnight.

Should You Make This Switch?

Yes, if you:

  • Are a developer comfortable with Nuxt/Vue
  • Want $0 hosting with Cloudflare Pages or similar
  • Care about owning your content in portable formats
  • Are tired of CMS pricing games
  • Want your content versioned in Git alongside your code

No, if you:

  • Need a visual page builder (stick with Framer or Webflow)
  • Want a CMS that non-technical clients can use independently
  • Need complex relational content (use a real database)
  • Don't know Vue/Nuxt and don't want to learn it for a portfolio

If you're in the "yes" camp, the setup is straightforward: scaffold a Nuxt 4 app, add the Content module, define your collections in content.config.ts, drop in your Markdown and YAML files, and deploy to Cloudflare Pages. The whole thing takes an afternoon.


Four CMSes, probably 60+ hours of migrations, and one hard lesson: the best CMS for a portfolio is the one that doesn't exist. Just files, in a repo, deployed for free.

My content is markdown and YAML now. If I want to move to Astro next year, I copy the files. If Cloudflare Pages shuts down tomorrow, I deploy somewhere else in 10 minutes. No export scripts. No migration hell. No $15/month for the privilege of hosting a list of my own projects.

What's the most you've ever paid monthly for a portfolio or personal site? I'm genuinely curious if anyone's topped my Framer + Sanity combo.