<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Agnel Nieves - Personal</title>
    <link>https://agnelnieves.com/blog/tag/personal</link>
    <description>Blog posts on Personal by Agnel Nieves.</description>
    <language>en-US</language>
    <lastBuildDate>Mon, 08 Jun 2026 16:00:53 GMT</lastBuildDate>
    <atom:link href="https://agnelnieves.com/blog/tag/personal/feed.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title><![CDATA[Why my Personal Site Is Also a Monorepo Now]]></title>
      <link>https://agnelnieves.com/blog/why-my-personal-site-is-also-a-monorepo-now</link>
      <guid isPermaLink="true">https://agnelnieves.com/blog/why-my-personal-site-is-also-a-monorepo-now</guid>
      <description><![CDATA[I turned my personal site into a monorepo because every side project I start wants to live somewhere. Here's the thinking, and what I'm planning next.]]></description>
      <content:encoded><![CDATA[<p>This is a note to myself as much as anyone else. A monorepo on a one-person site sounds like overkill. I went there anyway. Here is the honest reason, and what I&#39;m planning to do with it.</p>
<h2>The real reason</h2>
<p>I keep starting side projects. Some of them die. Others few stick. The ones that stick almost always want to live near my personal site, because they share the same brand, the same writing, the same identity. The terminal CLI behind <code>ssh agnelnieves.sh</code> is the obvious example. It reads from this site&#39;s API, it carries my voice, it is the same project in a different shape. But sometimes they have nothing to do with React or Tailwind, and it should not have to pretend to.</p>
<p>So the actual problem the monorepo solves for me is not Google scale or Vercel scale or any other scale. I just wanted a single place where my personal stuff lives, and I want each piece to stay clean and separate without me having to invent a new repo every time an idea shows up. Compartmentalize. Separate the concerns. Keep things tidy. Make the next thing cheap to start.</p>
<p>Before this week, the layout was a Next.js app with a Rust CLI in a sibling folder, sharing one <code>package.json</code> that did not care about it. That worked until I started writing down all the other things I want to ship from here, and the folder names started overlapping.</p>
<h2>What I&#39;m planning to add</h2>
<p>These are the side projects that are already drawn on a napkin somewhere:</p>
<ul>
<li>An automatic resume generator. The data lives here already (work history, projects, links). I want to feed it into a Resume builder package that renders to PDF, to a <code>/resume</code> page, and to a JSON endpoint for the CLI, all from one source. Maintaining up to date resumes are a huge pain of mine, so one of those things which is worth automating.</li>
<li>A social media post pipeline. Take a blog post I just published, generate the X thread, the LinkedIn version, and the headline-friendly image, all from code. Tag what posted where so nothing gets sent twice.</li>
<li>More CLI commands. The Rust binary is going to grow. Just for fun. </li>
<li>Probably something with AI agents. Some helper that drafts things based on my writing history.</li>
<li>Games, ideas, whatever else shows up.</li>
</ul>
<p>I do not want to make one of those a folder inside <code>src/</code>. Not because it would not work, but because they are not part of the Next.js app and they should not have to be. They are their own thing. They should have their own dependencies, their own build, their own deployments if they need one. A monorepo was the cheapest way I know to give each of them its own room without making me run <code>bun init</code> in a new GitHub repo every time and then forgetting which one had the latest version of my bio.</p>
<h2>What the layout looks like now</h2>
<pre><code>.
├── apps/
│   ├── web/         the Next.js site you are reading
│   └── cli/         the Rust binary behind ssh agnelnieves.sh
└── packages/
    └── tsconfig/    shared TypeScript presets, room for more
</code></pre>
<p><code>apps/</code> is for things I ship. <code>packages/</code> is for things those apps share. Right now there is only one shared package, on purpose. I do not want to invent abstractions before they have a second consumer. The day the resume generator and the social media tool both want the same &quot;load my blog posts&quot; helper, I will pull it into <code>packages/content</code> and let both of them depend on it. Until that day, it stays inside the Next.js app.</p>
<p>The tooling underneath is the same Rust-first stack I have written about before. Bun for the lockfile and the workspaces. Turborepo for the task graph. Biome and oxlint for the linters. Cargo for the Rust side. None of that is new. What is new is that they all sit inside one <code>turbo run</code>, and the cache means that editing a blog post does not re-typecheck the CLI, and editing the CLI does not rebuild the site. That is the whole point.</p>
<p>If you want the numbers (I do, because I like metrics): a clean rebuild with nothing changed runs in 67 milliseconds across both apps. That is the cache talking. The first cold build is about 80 seconds, mostly because the Rust binary is link-time optimized. Subsequent commits are nearly free. Pre-commit hooks stay out of my way. That is the day-to-day payoff.</p>
<h2>What I almost talked myself out of</h2>
<p>A few times during the migration I thought &quot;this is too much for a personal site.&quot; It would have been faster to keep going with the old layout for another year. The Rust CLI was already working. Nothing was actually broken.</p>
<p>What flipped me back was looking at the list of side projects I had stopped because they did not have a home. Three of them were dead by the same path: I wanted to ship a thing, I did not want to create a new repo for it, I tried to wedge it into this site as a folder, it felt wrong, I lost interest. The friction was not the code. The friction was that I did not have a clean place to put it. Sometimes my ideas/side projects are just experimental. Just as a way to do something fun or different.</p>
<p>A monorepo is, for me, a way of pre-committing to that clean place existing. The next time I want to start a small thing, it goes in <code>apps/whatever-it-is</code> or <code>packages/whatever-it-is</code>. I do not have to make any decisions about hosting, repo naming, or where it should live. The decision is already made.</p>
<h2>Things that broke, briefly, so future me knows</h2>
<p>There were three real hitches. I am writing them down because I will hit them again.</p>
<p>The first was a hoisting thing. The Next.js code imported <code>viem</code>, but <code>viem</code> was not in the <code>package.json</code>. It had been getting pulled in transitively through another package, and the flat <code>node_modules</code> made it look like it was installed. The minute I turned on bun workspaces, bun switched to isolated installs, and <code>viem</code> was no longer reachable from where the code expected it. The fix is one line. The lesson is that workspaces will surface every latent assumption your old install had been quietly covering for. Treat them as bugs the workspaces helped you find, not as new problems the workspaces caused.</p>
<p>The second was Vercel. Next.js 16 plus bun&#39;s isolated install plus Vercel&#39;s monorepo defaults collide in a way that the docs do not warn you about. The build fails locally and on Vercel until you set the project&#39;s Root Directory to <code>apps/web</code> in the Vercel dashboard and pin <code>turbopack.root</code> and <code>outputFileTracingRoot</code> in <code>next.config.ts</code>. The Vercel CLI cannot change Root Directory for you. You have to click it in the dashboard. I spent an embarrassing amount of time discovering this.</p>
<p>The third was that <code>vercel link</code> from inside <code>apps/web/</code> overwrites your <code>.env.local</code> with whatever the Vercel project has. If you had local-only secrets in there, they are gone. Back up first.</p>
<p>If you ever do this migration on your own site and want the working version of next.config.ts, the relevant bit lives in the actual repo and is referenced in <a href="/TOOLCHAIN.md">the toolchain doc</a>.</p>
<h2>What I want this to be</h2>
<p>I want this site to be the thing I tinker with when I am bored, without it feeling like I am about to make a mess. I want every side project to have a room. I want the resume to update itself the next time I add a project. I want the CLI to grow without dragging the website along with it. I want to add a third runnable thing in two months without thinking about it for more than five minutes.</p>
<p>A monorepo is just the shape that makes that possible without making me feel like I am building infrastructure when I should be writing.</p>
<p>If you are one person and you keep starting things that go nowhere because they do not have a home, I would genuinely consider doing this. The migration is a single afternoon. The rest of the time, it stays out of your way and just lets you start the next thing.</p>
<h2>Related</h2>
<ul>
<li><a href="/blog/rust-owns-the-javascript-toolchain-in-2026">Rust owns the JavaScript toolchain in 2026</a></li>
<li><a href="/blog/building-a-terminal-portfolio-you-can-ssh-into">Building a terminal portfolio you can SSH into</a></li>
<li><a href="https://turborepo.dev/docs">Turborepo</a></li>
<li><a href="https://www.remotion.dev/">Remotion</a> (how <code>packages/video</code> at basement works)</li>
</ul>
]]></content:encoded>
      <pubDate>Fri, 05 Jun 2026 00:00:00 GMT</pubDate>
      <author>agnel@agnelnieves.com (Agnel Nieves)</author>
      <dc:creator><![CDATA[Agnel Nieves]]></dc:creator>
      <category>Monorepo</category>
      <category>Turborepo</category>
      <category>Bun</category>
      <category>Next.js</category>
      <category>Rust</category>
      <category>Personal</category>
    </item>
  </channel>
</rss>