Most portfolio tutorials reach for a database immediately. But for a personal site with a single admin, a database adds infrastructure overhead without meaningful benefit. JSON files on the filesystem, with Next.js server actions and revalidatePath, give you the same DX with zero ops burden.
The Data Layer
Two utility functions — readData<T>(filename) and writeData<T>(filename, data) — wrap fs.promises.readFile and writeFile. Every domain module (projects.ts, skills.ts, blogs.ts) calls these with typed generics. Consistent, simple, and easy to swap for a real database later.
Cache Invalidation with revalidatePath
After every write, call revalidatePath('/') and the relevant sub-path. Next.js purges the cached RSC payload, and the next page load reflects the update instantly. No polling, no webhooks, no complexity.
When to Graduate to a Database
If you need multiple concurrent editors, row-level access control, full-text search, or a deployment platform that doesn't support writable filesystem, it's time for a database. Until then, JSON files are perfectly fine — and they're trivially version-controlled in git.