Back to the Monolith: AI Cost, Context, and our Changing Priorities
Skip to main content<br>SHEPHERD ANNOUNCES $42M SERIES B LED BY INTACT<br>READ MORE
Close Announcement Banner
INDUSTRIES
Resources
Careers
AboutAbout<br>About
ContactContact<br>Contact
INDUSTRIES
Resources
Careers
AboutAbout<br>About
ContactContact<br>Contact
Engineering & Product
Back to the Monolith: AI Cost, Context, and our Changing Priorities
Eli Kirmayer<br>Software Engineer<br>July 30, 2026
Most of Shepherd's architecture existed to compensate for our coordination limits, but AI-driven development removed that need to compensate. We merged our polyrepo into a monorepo, collapsed it into a single Next.js monolith, and cut our development cycle from nearly an hour to under 10 minutes.<br>For the last 5 years, Shepherd’s insurance platform operated on what had been industry best practice. We split our frontend and backend services into separate repositories so our teams could operate independently. Barring the occasional broken deploy, this process served us incredibly well. Shepherd is uniquely positioned: as a predominantly internal platform, we can move faster than a team shipping to millions of users. It does not let us be careless, our users are the underwriters pricing live submissions, and they notice everything. But we can take risks that allow us to invest deeply in developer efficiency.<br>Why Monolith? What Changed?<br>Since I joined Shepherd, our biggest problem has been keeping the contract between our frontend and backend services in sync. We rarely shipped a breaking change, but when we did, it could cost us 10 or 15 minutes of unexpected downtime that hurt both our users and our engineers’ pride. We had floated the idea of a monorepo and shared types, but our cost estimate was almost entirely in engineer hours, blocked most by coordination amongst different teams. A single engineer never had enough time to put in the work and make it happen, and we couldn’t justify handing it to more than one.<br>And then the cost disappeared. As models improved, so did the amount of code Shepherd engineers were producing. The more code we produced, the more architectural context an agent had to carry, and the more important it became to preserve that context and minimize rot. An agent working across two repos, a GraphQL schema, and multiple service boundaries burns tokens and attention reconstructing how those services work together. With AI-assisted development, an incredibly demanding harness just takes iteration, and iteration is substantially cheaper than an engineer trying and failing to define every parameter up front. Through repeated testing and improvements to the harness, we found that colocating our code reduced context usage by up to 40% on the same task. That made reorganizing our code economically obvious, but we could take it even further with a monolith.<br>Monorail: The Migration<br>Before the change, Shepherd’s platform consisted of two separate applications. Goldengate was our backend Node.js server on AWS that exposed GraphQL. Brooklyn was our frontend Next.js SPA on Vercel that communicated with it. Two repos, two deployments, two sets of infrastructure, and a schema contract between them that every feature had to cross.<br>Monorail was a single platform, a brand new third (and final) service bridging the gap between the two. We made an entirely new Next.js application on Vercel, backed by Neon Postgres, and started from scratch. We ran the whole thing in four beats, and the sequencing mattered more than any single decision. We would derisk with a smoke test, run in shadow mode, cut over in one move, then distribute the tail-end migration with AI-assisted tooling.<br>The process here was just as important to us as the end result. It was essential that an engineer shouldn’t need to know about the migration until Monorail was ready for them. We started off small, without a big rewrite, and ran a single smoke test. We imported a few pieces of the legacy code into the new application and made sure deployments work and all builds were green.<br>The strategy we settled on was to mount, not rewrite. Our Goldengate backend service got mounted inside Monorail. The entire GraphQL schema engine was served, completely unchanged, through an internal API route. Every API endpoint, every webhook, and every external service got its own Next.js route. Brooklyn’s frontend routes were programmatically imported by a script that allowed the rest of our team to keep developing, unaware of the work going on. The PR that brought Monorail to life consisted of the bare-bones skeleton of a Next.js app, 200 page files, and the script that traversed Brooklyn and generated them. Nearly every file was three lines long:
// monorail/src/app/u/carriers/page.tsx<br>'use client';<br>export { default } from '@brooklyn/app/u/carriers/page';<br>export * from '@brooklyn/app/u/carriers/page';That’s it. Our migration has begun, and it brought us complete developer parity with a direct reference to...