민준
US - --:--:--
DEVELOPMENT

6 min read

Why I turnedmy portfoliointo a monorepo

Every project starts simple. But when the portfolio gained a blog, quotes and an admin panel, it became clear that a single repo wouldn't cut it. This is the story of how I organized everything with Turborepo.

Victor M. Santos@soulhirolabs

March 16, 2026

When a single repository isn't enough.

March 2026

The turning point

Before this portfolio, I had already built others. Several, actually. Different designs, different repositories, but always the same structure: a Next.js project with everything inside.

And it worked. Until I decided this portfolio was going to be different.

This time it wasn't just a project showcase. I wanted a blog, a quote form that collects everything at once, a projects page with full case studies. And if I had all of this on the public site, I needed somewhere to manage it.

Quotes coming in, inbox messages, blog posts to review. Was I going to put all of that inside the same portfolio repository?

The problem with everything together

I already knew how it would end. The src folder would grow, files would multiply, and at some point I'd be spending time figuring out where things are instead of coding.

But it wasn't just about organization. There were practical issues that bothered me:

Mixed performance profiles — the public portfolio needs to be light and fast. The admin handles databases, integrations and heavy logic. Completely different profiles sharing the same build

Unnecessary middleware — authentication, route protection, session checks. The portfolio doesn't need any of that. But with everything together, middleware runs for all routes

Coupled deploys — a change in the admin forced a full portfolio rebuild. And vice versa. Build time growing for no reason

Limited customization — each app has its own identity. The portfolio has one visual language, the admin has another. With everything together, any customization becomes a mess of conditionals

The decision was clear: separate.

DECISION
It wasn't a matter of "monorepo is better." It was a matter of: what I'm building needs more than one app. And if it needs more than one app, it makes sense for them to live together.

The structure that emerged

I set up the monorepo with Turborepo and pnpm workspaces. Today it has two apps and several shared packages:

apps/web — the public portfolio. Blog, projects, quotes, contact. Runs as lightweight as possible, focused on performance and SEO

apps/admin — admin panel. Manages quotes, messages, blog posts, social media publishing. This is where the heavy logic lives

And the shared packages are what ties everything together:

packages/ui — interface components reused across both apps

packages/database — Drizzle schema, Neon (PostgreSQL) connection, fully typed end to end

packages/sanity — client, GROQ queries, types and CMS utilities

packages/email — email templates with React Email (confirmation, reply, newsletter)

WHY TURBOREPO?

Turborepo manages dependencies between packages and parallelizes builds. If I change packages/ui, it knows which apps need to be rebuilt. A single pnpm dev at the root spins up everything. A deploy on Vercel only builds the app that changed.

What surprised me

The first thing that surprised me was pnpm dev. One command at the root and both apps spin up simultaneously, each on its own port. Sounds simple, but when you're used to opening two terminals and running two separate projects, it's a huge difference in your daily workflow.

The second was real sharing. I change a component in packages/ui and it updates in both apps instantly. I change the database schema in packages/database and both admin and web already have access to the updated types. No publishing packages, no copying files. One source of truth.

And the third was realizing how much better each app breathes when separated. The portfolio builds in seconds because it doesn't carry the admin's complexity. The admin can have its own heavy dependencies without affecting the public site's load time. Each one does its thing, without getting in the other's way.

What it cost

Not everything was smooth. Setting up shared imports between packages took work. Not because it was conceptually hard, but because the errors that showed up were confusing — module resolution issues, TypeScript complaining about paths, exports that weren't recognized.

None of these errors were impossible to fix. But each one took longer than it should to diagnose, because error messages rarely pointed to the real problem. You'd think it was the import, but it was the exports field in package.json. You'd think it was TypeScript, but it was the field order in tsconfig.

"The hardest part of a monorepo isn't the architecture. It's convincing TypeScript that your packages exist."

What I'd do differently

If I started from scratch today, I'd make the same choice. But I would have defined the shared package structure from day one, instead of extracting things as needed. When you extract later, you end up with broken imports and refactors that could have been avoided.

I would also have spent more time upfront understanding how each package's package.json needs to be configured. Most of the errors I had came from poorly defined exports. One hour reading the docs at the start would have saved hours of debugging later.

This is just the beginning

The monorepo opened doors I hadn't thought of when I started. The ability to add new apps without reconfiguring everything, to have a codebase that grows in an organized way, to share without duplicating. There's more coming.

I plan to document each addition here on the blog — what I did, why I did it, and what I learned.

If you want to follow this journey, find me on LinkedIn. And if you have a project in mind, check out the quote form — that's exactly what it's there for.

"Organization isn't about having less code. It's about knowing where everything lives."

MONOREPOTURBOREPONEXT.JSARQUITETURAPNPM

Victor M. Santos

Engenheiro de Software & Product Designer. Construindo produtos digitais com visão sistêmica.

Ver todos os artigos →
READ ALSO

© 2026 Victor M. Santos