Context
The way designers build portfolios keeps changing. Over the last decade I've gone from PDF to Notion, then Webflow, Figma Sites, and now vibe-coding. Others use Dribbble or Behance to get discovered, but those platforms own the layout and the story. Your own site is the one place you control both.
But the real question was never the tool. It was who it's really for. What does a recruiter need to grasp quickly? What does another designer want to dig into? And how do I make it fun and easy to maintain?
What I want from a portfolio changed too. I've leaned toward clarity over process, signal over volume, and a voice that sounds like me.
AI is what finally let me build all of that myself. It's more flexible than the platforms before it, with no monthly fee. Built this way, a portfolio stops being proof of skills and becomes a reflection of how you think. This site is my current answer.
Challenges
| Challenge | Why it matters |
|---|---|
| Every update meant editing code | A new project or a one-line fix needed a code change and a deploy. Too slow to keep fresh. |
| Site builders didn't fit | Templates looked generic and couldn't match my type, spacing, and components. |
| Writing should feel like writing | Publishing a case study should be as easy as writing a Notion doc, not a coding task. |
| Consistency across pages | Every page had to follow the same design rules without me checking each one by hand. |
Goals
| Goal | Target outcome |
|---|---|
| Publish without code | Add or edit a project in Notion and see it live, with no deploy. |
| Stay on-brand | Every page uses my design system: the same type, spacing, and components. |
| Own the whole build | Design and build it myself, end to end, fast. |
| Keep it low-maintenance | A simple stack I can run and update on my own for years. |
Results
| Metric | Result |
|---|---|
| Time to publish | Minutes, from Notion to live |
| Content I control | Case studies and articles, all edited in Notion |
| Build | Solo, with Claude Code |
| Cost | Runs on Notion's free plan and low-cost hosting |
The build
The CMS
Notion is the content source. I keep two databases, one for case studies and one for articles. Each page's properties become the metadata on the site, and the page body becomes the content. The site connects through an internal Notion integration: I share the databases with it, and it reads them with a secret key kept out of the code. I only added the properties I use, and each one drives something on the page.
| Property | Why it's there |
|---|---|
| Title | Names the case study and gives it a clean, shareable URL. |
| Company, Role, Team | Gives a recruiter the context at a glance: who it was for and what I did. |
| Timeline | Signals when the work happened and how recent it is. |
| Platform, Industry, Focus | Drive the filters so visitors can quickly find the work they want to see (industry, platform, focus). |
| Cover | Gives each tile a visual hook and sets the hero image, so the work invites a click. |
| Description, Excerpt | A short subtitle that helps visitors decide what to open, and powers SEO and link previews. |
| Status | Lets me draft privately and publish only when a case study is ready. |
| Password | Keeps sensitive work private, so I can share it with recruiters, not the whole internet. |
Rendering
A renderer I built with Claude Code maps each Notion block to my own components, so the output always matches my design system.
| Layer | Approach | Tools |
|---|---|---|
| Framework | Server-rendered for speed and SEO | Next.js, TypeScript |
| Styling | Design tokens and utilities, no stray CSS | Tailwind CSS |
| Content | Fetched from Notion's API, cached and auto-refreshed | Notion API |
| Rendering | Each Notion block mapped to an on-brand component | Claude Code |
| Design system | Tokens → components → pages, consistent everywhere | Figma, Claude Code |
| Version control | History, branches, and a safety net for every change | Git, GitHub |
| Deployment | Builds and ships on every push to main | Vercel |
Style guide
Every component also renders on a living style guide that imports the same code the site uses, so the design system can’t quietly drift. I check changes there before they ship.
Reflection
The goal was never to build a CMS. It was to make writing and shipping easy enough that I’d keep the site alive. And that part worked.
What I learned
- Notion is a lovely place to write, but a loose CMS. Mapping its blocks to my own components keeps the design tight. It also brings quirks, like image links that expire and content that only refreshes on a delay.
- Owning the whole stack pays off. Design and code decisions feed each other, and nothing gets lost in a handoff.
- The speed of AI comes from the loop, not blind trust. Describe it, read the diff, then check it in the browser.
- A living style guide is what keeps everything consistent. Without it, small drifts quietly pile up.
- Notion is great for writing, but a loose CMS. Mapping its blocks to my own components keeps the design tight.
- Owning the whole stack pays off. Design and code decisions feed each other.
- With AI, the speed comes from the loop: describe, review the diff, check it in the browser.
What I'd improve
- Publish the moment I hit save, with Notion webhooks instead of a refresh interval.
- Cache Notion's images properly, so pages load faster and don't lean on links that expire.
- Add a draft preview, so I can see a case study before it goes live.
- Grow the renderer to cover more Notion blocks as I reach for them.
- Publish instantly with Notion webhooks, instead of a refresh interval.
- Cache Notion images so pages load faster and don’t rely on links that expire.
