ryer.io

Collapsing Three Projects Into One Monorepo

TL;DR

  • Three separate projects — Go/Remix timeline, Next.js Connect, Hugo journal — became one repository.
  • Kept every project’s git history by adding each as a remote and fetching, rather than copying files in.
  • Nested .git directories have to go; submodules would have defeated the purpose.
  • Container sizes were the surprise: Next.js 457MB, Remix 157MB, Hugo 5MB.
  • Vibe coding got me there fast, with intervention needed whenever the AI lost context or repeated itself.

This started because I wanted to learn Go, which produced a site at go.ryer.io with the backend and timeline functionality on Postgres with a Remix frontend. Then I added a Journal app converting voice notes to blog posts through an AI pipeline into Hugo, and a Connect site in Next.js.

Three projects, three runtimes, three repositories. Today they became one thing under ryer.io.

Dockerising everything

Each service runs in its own container, with a custom script bringing them all up together for development. Different runtimes, one command, and they can actually talk to each other locally — which is the part that makes the arrangement workable day to day.

The container sizes were genuinely surprising:

App Size
Next.js 457MB
Remix 157MB
Hugo 5MB

Next.js at nearly half a gigabyte against Hugo’s 5MB is a striking ratio, and it’s feeding my inclination to move Connect off Next.js. That’s a lot of container for a site that could be static.

The monorepo migration

The thing I cared about was not losing history. Copying files into a new repository would have worked in five minutes and thrown away every commit, so I did it the longer way.

Pick a parent. After some back and forth I chose an existing project to house the others as subdirectories, keeping its git repository as the primary one.

Move the files. Using mv with glob patterns, making sure hidden files and .git folders came along rather than being silently skipped — the default glob behaviour will miss dotfiles and you won’t notice until later.

Merge the histories. Each project’s existing remote gets added to the master repository:

  • git remote add to link each sub-project
  • git fetch to pull their histories in
  • git commit for a clean starting point

Remove the nested .git directories. Git won’t host repositories inside repositories, and submodules would have kept the projects separate — which is precisely what I was trying to stop. Deleting the inner .git folders after their history had been fetched is what actually completes the merge.

Deployment

Reconfigured the GitLab CI/CD scripts for the new layout, deploying via Docker on Railway with parallelised CI so the different applications build together rather than in sequence.

Hosting disparate technologies under one top-level domain was the awkward part, along with reconciling Vercel and Docker configurations.

On vibe coding

I leaned hard on AI for this — exploratory and opportunistic, optimising for speed. It works, with a caveat I want to record honestly: I had to intervene whenever it misjudged context or repeated steps it had already done. It’s an accelerator that needs supervision, not a substitute for knowing what you’re doing.

The whole exercise was a good reminder to stay adaptive about tech choices. Next up is tweaking the Railway settings and finishing the deployment.