Everything as code: How we manage our company in one monorepo

2025-12-3020:05227227www.kasava.dev

Kasava is the AI-native platform purpose-built for product development. Plan, build, and monitor with AI-powered workflows.

Last week, I updated our pricing limits. One JSON file. The backend started enforcing the new caps, the frontend displayed them correctly, the marketing site showed them on the pricing page, and our docs reflected the change—all from a single commit.

No sync issues. No "wait, which repo has the current pricing?" No deploy coordination across three teams. Just one change, everywhere, instantly.

At Kasava, our entire platform lives in a single repository. Not just the code—everything:

kasava/                              # 5,470+ files TypeScript files
├── frontend/                       # Next.js 16 + React 19 application
│   └── src/
│       ├── app/                   # 25+ route directories
│       └── components/            # 45+ component directories
├── backend/                        # Cloudflare Workers API
│   └── src/
│       ├── services/              # 55+ business logic services
│       └── workflows/             # Mastra AI workflows
├── website/                        # Marketing site (kasava.ai)
├── docs/                           # Public documentation (Mintlify)
├── docs-internal/                  # 12+ architecture docs & specs
├── marketing/
│   ├── blogs/                     # Blog pipeline (drafts → review → published)
│   ├── investor-deck/             # Next.js site showing investment proposal
│   └── email/                     # MJML templates for Loops.so campaigns
├── external/
│   ├── chrome-extension/          # WXT + React bug capture tool
│   ├── google-docs-addon/         # @helper AI assistant (Apps Script)
│   └── google-cloud-functions/
│       ├── tree-sitter-service/   # AST parsing for 10+ languages
│       └── mobbin-research-service/
├── scripts/                        # Deployment & integration testing
├── infra-tester/                   # Integration test harness
└── github-simulator/               # Mock GitHub API for local dev

Why This Matters: AI-Native Development

This isn't about abstract philosophies on design patterns for 'how we should work.' It's about velocity in an era where products change fast and context matters.

AI is all about context. And this monorepo is our company—not just the product.

When our AI tools help us write documentation, they have immediate access to the actual code being documented. When we update our marketing website, the AI can verify claims against the real implementation. When we write blog posts like this one, the AI can fact-check every code example, every number, every architectural claim against the source of truth.

This means we move faster:

  • Documentation updates faster because the AI sees code changes and suggests doc updates in the same context
  • Website updates faster because pricing, features, and capabilities are pulled from the same config files that power the app
  • Blog posts ship faster because the AI can run self-referential checks—validating that our "5,470+ TypeScript files" claim is accurate by actually counting them
  • Nothing goes out of sync because there's only one source of truth, and AI has access to all of it

When you ask Claude to "update the pricing page to reflect the new limits," it can:

  1. Read the backend service that enforces limits
  2. Check the frontend that displays them
  3. Update the marketing site
  4. Verify the docs are consistent
  5. Flag any blog posts that might mention outdated numbers

All in one conversation. All in one repository.

This is what "AI-native development" actually means: structuring your work so AI can be maximally helpful, not fighting against fragmentation.

And it reinforces a shipping culture.

Everything-as-code means everything ships the same way: git push. Want to update the website pricing page? git push. New blog post ready to go live? git push. Fix a typo in the docs? git push. Deploy a backend feature? git push.

No separate CMSs to log into. No WordPress admin panels. No waiting for marketing tools to sync. No "can someone with Contentful access update this?" The same Git workflow that ships code also ships content, documentation, and marketing. Everyone on the team can ship anything, and it all goes through the same review process, the same CI/CD, the same audit trail.

This uniformity removes friction and removes excuses. Shipping becomes muscle memory.

Why Everything in One Repo?

1. Atomic Changes Across Boundaries (That AI Can Understand)

When a backend API changes, the frontend type definitions update in the same commit. When we add a new feature, the documentation can ship alongside it. No version mismatches. No "which version of the API does this frontend need?"

AI can see and validate the entire change in context.

When we ask Claude to add a feature, it doesn't just write backend code. It sees the frontend that will consume it, the docs that need updating, and the marketing site that might reference it. All in one view. All in one conversation.

Real example from our codebase—adding Asana integration:

commit: "feat: add Asana integration"
├── backend/src/services/AsanaService.ts
├── backend/src/routes/api/integrations/asana.ts
├── frontend/src/components/integrations/asana/
├── frontend/src/app/integrations/asana/
├── docs/integrations/asana.mdx
└── website/src/app/integrations/page.tsx

One PR. One review. One merge. Everything ships together.

Another example—keeping pricing in sync:

We have a single billing-plans.json that defines all plan limits and features:


{ "plans": { "free": { "limits": { "repositories": 1, "aiChatMessagesPerDay": 10 } }, "starter": { "limits": { "repositories": 10, "aiChatMessagesPerDay": 100 } }, "professional": { "limits": { "repositories": 50, "aiChatMessagesPerDay": 1000 } } }
}

The backend enforces these limits. The frontend displays them in settings. The marketing website shows them on the pricing page. When we change a limit, one JSON update propagates everywhere—no "the website says 50 repos but the app shows 25" bugs.

And AI validates all of it. When we update billing-plans.json, we can ask Claude to verify that the backend, frontend, and website are all consistent. It reads all three implementations and confirms they match—or tells us what needs fixing.

2. Cross-Project Refactoring

Renaming a function? Your IDE finds all usages across frontend, backend, docs examples, and blog code snippets. One find-and-replace. One commit.

3. Single Source of Truth

  • Dependencies: Shared tooling configured once
  • CI/CD: One pipeline to understand
  • Search: Find anything with one grep

The Structure: What Lives Where

Core Application

frontend/                        # Customer-facing Next.js app
├── src/
│   ├── app/                    # Next.js 15 App Router
│   │   ├── analytics/         # Semantic commit analysis
│   │   ├── bug-reports/       # AI-powered bug tracking
│   │   ├── chat/              # AI assistant interface
│   │   ├── code-search/       # Semantic code search
│   │   ├── dashboard/         # Main dashboard
│   │   ├── google-docs-assistant/
│   │   ├── integrations/      # GitHub, Linear, Jira, Asana
│   │   ├── prd/               # PRD management
│   │   └── ...                # 25+ route directories total
│   ├── components/            # 45+ component directories
│   │   ├── ai-elements/      # AI-specific UI
│   │   ├── bug-reports/      # Bug tracking UI
│   │   ├── dashboard/        # Dashboard widgets
│   │   ├── google-docs/      # Google Docs integration
│   │   ├── onboarding/       # User onboarding flow
│   │   └── ui/               # shadcn/ui base components
│   ├── mastra/               # Frontend Mastra integration
│   └── lib/                  # SDK, utilities, hooks

backend/                        # Cloudflare Workers API
├── src/
│   ├── routes/               # Hono API endpoints
│   ├── services/             # 55+ business logic services
│   ├── workflows/            # Mastra AI workflows
│   │   ├── steps/           # Reusable workflow steps
│   │   └── RepositoryIndexingWorkflow.ts
│   ├── db/                   # Drizzle ORM schema
│   ├── durable-objects/      # Stateful edge computing
│   ├── workers/              # Queue consumers
│   └── mastra/               # AI agents and tools

These two talk to each other constantly. Having them in the same repo means:

  • API changes include frontend updates
  • Type safety across the boundary
  • Shared testing utilities

Marketing Properties

website/                        # kasava.ai marketing site
├── src/
│   ├── app/                   # Landing pages, blog
│   ├── components/            # Shared marketing components
│   └── lib/                   # Utilities

marketing/
├── blogs/
│   ├── queue/
│   │   └── drafts/           # Ideas and drafts
│   ├── review/               # Ready for editing
│   └── published/            # Live on the site
├── investor-deck/            # Next.js presentation (not PowerPoint!)
└── email/
    ├── CLAUDE.md             # Email writing guidelines
    └── mjml/                 # 7+ email campaign loops
        ├── loop-1-welcome/
        ├── loop-2-github-connected/
        ├── loop-3-trial-conversion/
        └── ...

Yes, even blog posts are code. They're Markdown files with frontmatter, versioned in Git, reviewed in PRs. Email templates are MJML that version controls our entire customer communication system.

Even our investor deck is code — a Next.js 16 static site with 17 React slide components, keyboard navigation, and PDF export. No PowerPoint, no Google Slides. When we update metrics or messaging, it's a code change with full Git history, reviewed in a PR, and deployed with git push.

Why this matters:

  • Marketing can update copy without engineering
  • Changes are reviewed and tracked
  • Rollback is one git revert away
  • Email campaigns are testable and diffable

Documentation

docs/                           # Public docs (Mintlify)
├── index.mdx                  # Landing page
├── quickstart.mdx             # Getting started
├── demo-mode.mdx              # Demo mode guide
├── features/                  # Product features
│   ├── ai-chat.mdx
│   ├── code-intelligence.mdx
│   ├── code-search.mdx
│   └── prds.mdx
├── integrations/              # Integration guides
│   ├── github.mdx
│   ├── linear.mdx
│   ├── jira.mdx
│   └── asana.mdx
└── bug-tracking/              # Bug tracking docs

docs-internal/                  # Engineering knowledge base
├── GITHUB_CHAT_ARCHITECTURE.md
├── QUEUE_ARCHITECTURE_SUMMARY.md
├── UNIFIED_TASK_ANALYTICS_QUEUE.md
├── features/                  # Feature specs
├── migrations/                # Migration guides
├── plans/                     # Implementation plans
└── research/                  # Research notes

Public docs deploy automatically when we push. Internal docs are searchable alongside code—when someone asks "how does the queue work?", they find the actual architecture document, not a stale wiki page.

External Services

external/
├── chrome-extension/          # WXT-based bug capture tool
│   ├── entrypoints/          # popup, content scripts, background
│   ├── lib/                  # Screen capture, console logging
│   ├── components/           # React UI components
│   └── wxt.config.ts         # WXT configuration
│
├── google-docs-addon/        # @helper mentions in Docs
│   ├── Code.gs              # Main Apps Script (18KB)
│   ├── Sidebar.html         # React-like UI (26KB)
│   ├── Settings.html        # Configuration UI
│   └── appsscript.json      # Manifest
│
└── google-cloud-functions/
    ├── tree-sitter-service/  # AST parsing
    │   └── Supports: JS, TS, Python, Go, Rust,
    │       Java, C, C++, Ruby, PHP, C#
    └── mobbin-research-service/  # UX research

These deploy to completely different platforms (Chrome Web Store, Google Apps Script, GCP) but live together because:

  • They share API contracts with the main app
  • Changes often span boundaries
  • One team maintains everything

Development Infrastructure

github-simulator/              # Mock GitHub API for local dev
infra-tester/                  # Integration test harness
scripts/
├── google-cloud/             # GCP deployment scripts
├── test-credentials.ts       # Credential testing
└── test-webhook-integration.ts

Local development shouldn't require external services. Mock servers live with the code they simulate.

What Deploys Where

ComponentTech StackDeploys To
FrontendNext.js 15, React 19, Tailwind v4Vercel
BackendCloudflare Workers, Hono, MastraCloudflare
WebsiteNext.js, custom componentsVercel
Investor DeckNext.js, custom componentsVercel
DocsMintlify MDXMintlify
Chrome ExtensionWXT, React, TailwindChrome Web Store
Google Docs Add-onApps Script, HTMLGoogle Workspace Marketplace
Tree-sitter ServiceNode.js, GCP FunctionsGoogle Cloud
Email TemplatesMJMLLoops.so

How We Make It Work

No Workspaces (And That's Fine)

We deliberately don't use npm/yarn workspaces. (Well, we do in one specific use case but that's for another post.) Each directory is its own independent npm project:

cd frontend && npm install cd backend && npm install cd external/chrome-extension && npm install  

Why? Simplicity. No hoisting confusion. No "which version of React am I actually getting?" Each project is isolated and predictable.

Selective CI/CD

We run 5 GitHub Actions workflows, each triggered by specific paths:


name: Frontend Tests
on: push: paths: - "frontend/**" - ".github/workflows/frontend-tests.yml"


name: Backend Tests
on: push: paths: - "backend/**" - ".github/workflows/backend-tests.yml"


name: Tree-sitter Tests
on: push: paths: - "external/google-cloud-functions/tree-sitter-service/**"

Change the Chrome extension? Only relevant tests run. Update the backend? Backend tests plus any integration tests that depend on it.

The CLAUDE.md Convention

Every major directory has a CLAUDE.md file that documents:

  • What this code does
  • Tech stack and versions
  • Quick start commands
  • Architecture decisions
  • Common patterns
CLAUDE.md                          # Root-level overview
├── frontend/CLAUDE.md            # Next.js 15, React 19, Tailwind v4
├── backend/CLAUDE.md             # Cloudflare Workers, Hono, Mastra
├── external/chrome-extension/CLAUDE.md
├── external/google-cloud-functions/CLAUDE.md
└── marketing/email/CLAUDE.md     # MJML email guidelines

This isn't just for humans—AI coding assistants read these files. When Claude Code works on our frontend, it reads frontend/CLAUDE.md and knows we're using Next.js 15 with React 19, npm (not pnpm), and specific patterns.

Consistent Tooling

One configuration, everywhere:

.prettierrc              # Formatting (all JS/TS)
.eslintrc               # Linting (shared rules)
tsconfig.json           # TypeScript base config

New developer? npm install in the directory you're working on. Everything works.

The Challenges (And How We Handle Them)

Challenge: Repository Size

Why it's not a problem (yet):

  • Clone time: ~20 seconds
  • Git operations: still snappy
  • We haven't needed sparse checkout, LFS, or shallow clones

When we might need to:

  • Large binary assets would go to R2/S3, not git
  • If we hit 1GB+, we'd look at shallow clones for CI
  • Truly independent services could be extracted

Challenge: Build Times

Problem: If everything is connected, does everything rebuild?

Reality: No. Each project builds independently:


cd frontend && npm run build cd backend && npm run build cd external/chrome-extension && npm run build

We use Turbopack for frontend dev (fast HMR), Wrangler for backend dev (fast reload), and WXT for extension dev (fast rebuild).

Challenge: Permission Boundaries

Problem: Not everyone should see everything.

Our situation: We're a small team. Everyone can see everything. That's a feature, not a bug—it enables cross-pollination.

If we grew and needed boundaries:

  • GitHub CODEOWNERS for review requirements
  • Branch protection rules
  • Potentially split truly sensitive codebases (but we'd resist this)

Challenge: Context Switching

Problem: Jumping between TypeScript (frontend), TypeScript (backend), Apps Script (Google add-on), and MJML (emails) feels disorienting.

Solutions:

  • Consistent patterns across projects (same linting, same formatting)
  • CLAUDE.md files explain context immediately
  • IDE workspace configurations

Conclusion

Our monorepo isn't about following a trend. It's about removing friction between things that naturally belong together, something that is critical when related context is everything.

When a feature touches the backend API, the frontend component, the documentation, and the marketing site—why should that be four repositories, four PRs, four merge coordination meetings?

The monorepo isn't a constraint. It's a force multiplier.

Kasava is built as a unified platform. See what we've built


Read the original article

Comments

  • By wrs 2025-12-3021:174 reply

    This is sort of a whole product, but it’s hardly managing the whole company. Financials? HR? Contracts? Pictures of the last team meeting?

    It just looks like a normal frontend+backend product monorepo, with the only somewhat unusual inclusion of the marketing folder.

    • By mjr00 2025-12-3023:182 reply

      It's worth noting with a few clicks from the linked article, you can find that this company is (at least according to LinkedIn) a single person. Which explains how the whole company can fit into a repo. But also makes you question how valuable the "insights" here are, like obviously a single-person project should be using a monorepo...

      • By wrs 2025-12-3023:22

        Ah, so "our" company is referring to "me and Claude"? Actually. Claude might be a pretty good co-founder. Half the job is therapy conversations anyway. :)

      • By mehmetkose 2025-12-3113:192 reply

        have you ever heart that google is also one repo? at least it was until 2015. don’t know the story later. So it doesn’t have to be one person company. yet they are making billions

        • By mjr00 2025-12-3118:10

          I'm not making any claims about monorepo being good or bad and I'm fully aware large companies have monorepos (or at least very large repos). I'm saying that the fact it's a one-person "company" needs to be taken into account when talking about how applicable their experience is to other companies.

        • By teaearlgraycold 2025-12-3117:40

          Google isn’t a monorepo since the acquisition of Android. That one never made it into google3.

    • By PunchyHamster 2025-12-3021:42

      Yes but AI! AI!

    • By vasco 2025-12-3023:04

      Not even infrastructure as code is in the repository from what one can see.

    • By webdevver 2025-12-3021:423 reply

      i am actually eagerly waiting for someone to show the real-deal: actually everything in a github repo, including 'artfiacts', or atleast those artifacts which can't be reconstructed from the repo itself.

      maybe they could be encrypted, and you could say "well its everything but the encryption key, which is owned in physical form by the CEO."

      theres a lot of power i think to have everything in one place. maybe github could add the notion of private folders? but now thats ACLs... probably pushing the tool way too far.

      • By b40d-48b2-979e 2025-12-3022:28

            maybe they could be encrypted, and you could say "well its everything but the
            encryption key, which is owned in physical form by the CEO."
        
        I don't see how this is any different from most projects where keys and the like are kept in some form of secrets manager (AWS services, GHA Secrets, Hashi Vault, etc.).

      • By kittoes 2025-12-310:29

        https://dev.azure.com/byteterrace/Koholint/_git/Azure.Resour...

        How close do you think this is? Deploys everything but the actual backend/frontend code.

      • By maccard 2025-12-310:49

        At a previous job we put compilers and standard libraries in version control, with custom tooling to pull the right version for what you need.

        We used p4 rather than git though.

  • By eddd-ddde 2025-12-3020:264 reply

    I am a huge monorepo supporter, including "no development branches".

    However there's a big difference between development and releases. You still want to be able to cut stable releases that allow for cherrypicks for example, especially so in a monorepo.

    Atomic changes are mostly a lie when talking about cross API functions, i.e. frontend talking to a backend. You should always define some kind of stable API.

    • By RaftPeople 2025-12-313:241 reply

      > including "no development branches"

      Can you explain this comment? Are you saying to develop directly in the main branch?

      How do you manage the various time scales and complexity scales of changes? Task/project length can vary from hours to years and dependencies can range from single systems to many different systems, internal and external.

      • By eddd-ddde 2025-12-315:053 reply

        Yeah, all new commits are merged to main.

        The complexity comes from releases. Suppose you have a good commit 123 were all your tests pass for some project, you cut a release, and deploy it.

        Then development continues until commit 234, but your service is still at 123. Some critical bug is found, and fixed in commit 235. You can't just redeploy at 235 since the in-between may include development of new features that aren't ready, so you just cherry pick the fix to your release.

        It's branches in a way, but _only_ release branches. The only valid operations are creating new releases from head, or applying cherrypicks to existing releases.

        • By WorldMaker 2025-12-3115:41

          That's where tags are useful because the only valid operations (depending on force push controls) are creating a new tag. If your release process creates tag v0.6.0 for commit 123 your tools (including `git describe`) should show that as the most recent release, even at commit 234. If you need to cut a hotfix release for a critical bug fix you can easily start the branch from your tag: `git switch -c hotfix/v0.6.1 v0.6.0`. Code review that branch when it is ready and tag v0.6.1 from its end result.

          Ideally you'd do the work in your hotfix branch and merge it to main from there rather than cherry picking, but I feel that mostly because git isn't always great at cherry picking.

        • By RaftPeople 2025-12-3117:081 reply

          > Suppose you have a good commit 123 were all your tests pass for some project, you cut a release, and deploy it.

          And you've personally done this for a larger project with significant amount of changes and a longer duration (like maybe 6 months to a year)?

          I'm struggling to understand why you would eliminate branches? It would increase complexity, work and duration of projects to try to shoehorn 2 different system models into one system. Your 6 month project just shifted to a 12 to 24 month project.

          • By eddd-ddde 2026-01-011:171 reply

            Can you clarify why it would impact project duration?

            In my experience development branches vastly increase complexity by hiding the integration issues until very late when you try to merge.

            • By RaftPeople 2026-01-012:071 reply

              The reason I said it would impact duration is the assumption that the previous version and new version of the system are all in the code at one time, managed via feature flags or something. I think I was picturing that due to other comments later in the thread, you may not be handling it that way.

              Either way, I still don't understand how you can reasonably manage the complexity, or what value it brings.

              Example:

              main - current production - always matches exactly what is being executed in production, no differences allowed

              production_qa - for testing production changes independent of the big project

              production_dev_branches - for developing production changes during big project

              big_project_qa_branch - tons of changes, currently being used to qa all of the interactions with this system as well as integrations to multiple other systems internal and external

              big_project_dev_branches - as these get finalized and ready for qa they move to qa

              Questions:

              When production changes and project changes are in direct conflict, how can you possibly handle that if everyone is just committing to one branch?

              How do you create a clean QA image for all of the different types of testing and ultimately business training that will need to happen for the project?

              • By eddd-ddde 2026-01-0123:211 reply

                It depends a lot on a team by team basis as different teams would like different approaches

                In general, all new code gets added to the tip of main, your only development branch. Then, new features can also be behind feature flags optionally. This allows developers to test and develop on the latest commit. They can enable a flag if they are interested in a particular feature. Ideally new code also comes with relevant automated tests just to keep the quality of the branch high.

                Once a feature is "sufficiently tested" whatever that may mean for your team it can be enabled by default, but it won't be usable until deployed.

                Critically, there is CI that validates every commit, _but_ deployments are not strictly performed from every commit. Release processes can be very varied.

                A simple example is we decide to create a release from commit 123, which has some features enabled. You grab the code, build it, run automated tests, and generate artifacts like server binaries or assets. This is a small team with little SLAs so it's okay to trust automated tests and deploy right to production. That's the end, commit 123 is live.

                As another example, a more complex service may require more testing. You do the same first steps, grab commit 123, test, build, but now deploy to staging. At this point staging will be fixed to commit 123, even as development continues. A QA team can perform heavy testing, fixes are made to main and cherry picked, or the release dropped if something is very wrong. At some point the release is verified and you just promote it to production.

                So development is always driven from the tip of the main branch. Features can optionally be behind flags. And releases allow for as much control as you need.

                There's no rule that says you can only have one release or anything like that. You could have 1 automatic release every night if you want to.

                Some points that make it work in my experience are:

                1. Decent test culture. You really want to have at least some metric for which commits are good release candidates. 2. You'll need some real release management system. The common tools available like to tie together CI and CD which is not the right way to think about it IMO (example your GitHub CI makes a deployment).

                TL:Dr:

                Multiple releases, use flags or configuration for the different deployments. They could all even be from the same or different commits.

                • By RaftPeople 2026-01-0217:331 reply

                  > As another example, a more complex service may require more testing. You do the same first steps, grab commit 123, test, build, but now deploy to staging. At this point staging will be fixed to commit 123, even as development continues. A QA team can perform heavy testing, fixes are made to main and cherry picked, or the release dropped if something is very wrong. At some point the release is verified and you just promote it to production.

                  But how would you create that QA environment when it involves thousands of commits over a 6 month period?

                  • By eddd-ddde 2026-01-0219:331 reply

                    It totally depends on how you want to test releases. You can have nightlies that deploy the latest green commit every day, do some QA there, then once it is feature complete promote it to a stable release that only cherry picks fixes, then finally promote it to production.

                    It will be highly dependent on the kind of software you are building. My team in particular deals with a project that cuts "feature complete" releases every 6 months or so, at that point only fixes are allowed for another month or so before launch, during this time feature development continues on main. Another project we have is not production critical, we only do automated nightlies and that's it.

                    • By RaftPeople 2026-01-0220:42

                      > It totally depends on how you want to test releases.

                      For a big project, typically it involves deploying to a fully functioning QA environment so all functionality can be tested end to end, including interactions with all other systems internal to the enterprise and external. Eventually user acceptance testing and finally user training before going live.

        • By imiric 2025-12-319:121 reply

          I don't see how you're avoiding development branches. Surely while a change is in development the author doesn't simply push to main. Otherwise concurrent development, and any code review process—assuming you have one—would be too impractical.

          So you can say that you have short-lived development branches that are always rebased on main. Along with the release branch and cherry-pick process, the workflow you describe is quite common.

          • By ozozozd 2025-12-319:291 reply

            Their dev branch is _the_ development branch.

            They don’t do code reviews or any sort of parallel development.

            They’re under the impression that “releases are complex and this is how they avoid it” but they just moved the complexity and sacrificed things like parallel work, code reviews, reverts of whole features.

            • By eddd-ddde 2026-01-011:18

              I'm not sure where you got that from. There is a single branch, which obviously has code review, and reverts work just the same way.

              What there isn't, is long lived feature branches with non-integrated changes.

    • By lorey 2025-12-3021:075 reply

      Very interesting points. Would you mind sharing a few examples of when cherry-picking is necessary and why atomic changes are a lie?

      I'm using a monorepo for my company across 3+ products and so far we're deploying from stable release to stable release without any issues.

      • By Eridrus 2025-12-3021:432 reply

        Atomic changes are a lie in the sense that there is no atomic deployment of a repo.

        The moment you have two production services that talk to each other, you end up with one of them being deployed before the other.

        • By oooyay 2025-12-312:041 reply

          Atomicity also rarely matters as much as people think it does if contracts are well defined and maintained.

          • By Eridrus 2025-12-3115:10

            A selling point of monorepos is that you don't need to maintain backwards compatible contracts and can make changes to both sides of an API at once.

        • By array_key_first 2025-12-3120:391 reply

          If you have a monolith you get atomic deployment, too.

          • By yencabulator 2026-01-0219:111 reply

            You lose atomic deployment and have a distributed system the moment you ship Javascript to a browser.

            Hell, you lose "atomic" assets the moment you serve HTML that has URLs in it.

            Consider switching from <img src=kitty.jpg> to <img src=puppy.jpg>. If you for example, delete kitty from the server and upload puppy.jpg, then change html, you can have a client with URL to kitty while kitty is already gone. Generally anything you published needs to stay alive for long enough to "flush out the stragglers".

            Same thing applies to RPC contracts.

            Same thing applies to SQL schema changes.

            • By array_key_first 2026-01-0223:341 reply

              They just refresh the page, it's not a big deal. It'll happen on form submission or any navigation anyway. Some people might be caught in a weird invalid state for, like, a couple minutes absolute maximum.

              • By yencabulator 2026-01-0223:381 reply

                If you're not interested in solving the problem, then don't claim to solve the problem.

                • By array_key_first 2026-01-0322:291 reply

                  Right, there's level of solutions. You can't sit here and say that a few seconds of invalid state on the front-end only for mayyyyybe .01% of your users is enough to justify a sprawling distributed system because "well deployments aren't atomic anyway!1!".

                  IMO, monorepos are much easier to handle. Monoliths are also easier to handle. A monorepo monolith is pretty much as good as it gets for a web application. Doing anything else will only make your life harder, for benefits that are so small and so rare that nobody cares.

                  • By yencabulator 2026-01-0322:541 reply

                    Monorepo vs not is not the relevant criteria. The difference is simply whether you plan your rollout to have no(/minimal) downtime, or not. Consider SQL schema migration to add a non-NULL column on a system that does continuous inserts.

                    • By array_key_first 2026-01-0520:431 reply

                      Again, that's trivial if you use up and down servers. No downtime, and to your users, instant deployment across the entire application.

                      If you have a bajillion services and they're all doing their own thing with their own DB and you have to reconcile version across all of them and you don't have active/passive deployments, yes that will be a huge pain in the ass.

                      So just don't do that. There, problem solved. People need to stop doing micro services or even medium sized services. Make it one big ole monolith, maybe 2 monoliths for long running tasks.

                      • By yencabulator 2026-01-0520:58

                        Magical thinking about monorepos isn't going to make SQL migrations with backfill instantaneous and occur simultaneously with the downtime you have while you switch software versions. You're just not familiar with the topic, I guess. That's okay. Please just don't claim the problem doesn't exist.

                        And yes, it's often okay to ignore the problem for small sites that can tolerate the downtime.

      • By ratorx 2025-12-3021:43

        Not sure what GP had in mind, but I have a few reasons:

        Cherry picks are useful for fixing releases or adding changes without having to make an entirely new release. This is especially true for large monorepos which may have all sorts of changes in between. Cherry picks are a much safer way to “patch” releases without having to create an entirely new release, especially if the release process itself is long and you want to use a limited scope “emergency” one.

        Atomic changes - assuming this is related to releases as well, it’s because the release process for the various systems might not be in sync. If you make a change where the frontend release that uses a new backend feature is released alongside the backend feature itself, you can get version drift issues unless everything happens in lock-step and you have strong regional isolation. Cherry picks are a way to circumvent this, but it’s better to not make these changes “atomic” in the first place.

      • By GeneralMayhem 2025-12-3021:383 reply

        Do you take down all of your projects and then bring them back up at the new version? If not, then you have times at which the change is only partially complete.

        • By cgio 2025-12-3023:10

          I would see a potentially more liberal use of atomic, that if the repo state reflects the totality of what I need to get to new version AND return to current one, then I have all I need from a reproducibility perspective. Human actions could be allowed in this, if fully documented. I am not a purist, obviously.

        • By rezonant 2025-12-3022:18

          Nah, these days the new thing is Vibe Deployments, just ship the change and pray.

        • By awesome_dude 2025-12-3022:201 reply

          People that Blue Green are doing that, aren't they?

          Canary/Incremental, not so much

          • By Denvercoder9 2025-12-3023:111 reply

            Blue/green might allow you to do (approximately) atomic deploys for one service, but it doesn't allow you to do an atomic deploy of the clients of that service as well.

            • By nkmnz 2025-12-310:032 reply

              Why that? In a very simple case, all services of a monorepo run on a single VM. Spin up new VM, deploy new code, verify, switch routing. Obviously, this doesn't work with humongous systems, but the idea can be expanded upon: make sure that components only communicate with compatible versions of other components. And don't break the database schema in a backward-incompatible way.

              • By Denvercoder9 2025-12-311:241 reply

                So yes, in theory you can always deploys sets of compatible services, but it's not really workable in practice: you either need to deploy the world on every change, or you need to have complicated logic to determine which services are compatible with which deployment sets of other services.

                There's a bigger problem though: in practice there's almost always a client that you don't control, and can't switch along with your services, e.g. an old frontend loaded by a user's browser.

                • By nkmnz 2026-01-038:25

                  The notion of external clients is a smell. If that’s the case, you need a compat layer between that client and your entrypoints, otherwise you’ll have a very hard time evolving anything. In practice, this can include providing frontend assets under previously cached endpoints; a version endpoint that triggers cache busting; a load balancer routing to a legacy version for a grace period… sadly, there‘s no free lunch here.

              • By awesome_dude 2025-12-310:09

                The only way I could read their answer as being close to correct is if the clients they're referring to are not managed by the deployment.

                But (in my mind) even a front end is going to get told it is out of date/unusable and needs to be upgraded when it next attempts to interact with the service, and, in my mind atleast, that means that it will have to upgrade, which isn't "atomic" in the strictest sense of the word, but it's as close as you're going to get.

      • By gorgoiler 2025-12-3022:402 reply

        If your monorepo compiles to one binary on one host then fine, but what do you do when one webserver runs vN, another runs v(N-1), and half the DB cluster is stuck on v(N-17)?

        A monorepo only allows you to reason about the entire product as it should be. The details of how to migrate a live service atomically have little to do with how the codebase migrates atomically.

        • By eddd-ddde 2025-12-315:11

          That's why I mention having real stable APIs for cross-service interaction, as you can't guarantee that all teams deploy the exact same commit everywhere at once. It is possible but I'd argue that's beyond what a monorepo provides. You can't exactly atomically update your postgres schema and JavaScript backend in one step, regardless of your repo arrangement.

          Adding new APIs is always easy. Removing them not so much since other teams may not want to do a new release just to update to your new API schema.

        • By bb88 2025-12-3023:031 reply

          But isn't that a self-inflicted wound then? I mean is there some reason your devs decided not to fix the DB cluster? Or did management tell you "Eh, we have other things we want to prioritize this month/quarter/year?"

          This seems like simply not following the rules with having a monorepo, because the DB Cluster is not running the version in the repo.

          • By Denvercoder9 2025-12-3023:241 reply

            Maybe the database upgrade from v(N-17) to v(N-16) simply takes a while, and hasn't completed yet? Or the responsible team is looking at it, but it doesn't warrant the whole company to stop shipping?

            Being 17 versions behind is an extreme example, but always having everything run the latest version in the repo is impossible, if only because deployments across nodes aren't perfectly synchronised.

            • By array_key_first 2025-12-3120:42

              This is why you have active/passive setup and you don't run half-deployed code in production. Using API contracts is a weak solution, because eventually you will write a bug. It's simpler to just say "everything is running the same version" and make that happen.

      • By tedmiston 2025-12-3021:40

        each deployment is a separate "atomic change". so if a one-file commit downstream affects 2 databases, 3 websites and 4 APIs (madeup numbers), then that is actually 9 different independent atomic changes.

    • By djhedges 2025-12-3021:512 reply

      We use a mono repo and feature flag new features which gives us the deployment control timing.

      • By imiric 2025-12-319:20

        I can guarantee that your codebase is spaghetti of conditional functionality that no developer understands, and that most of those conditionals are leftovers that are no longer needed, but nobody dares to remove.

        Feature flags are a good idea, but they require a lot of discipline and maintenance. In practice, they tend to be overused, and provide more negatives than positives. They're a complement, but certainly not a replacement for VCS branches, especially in monorepos.

      • By odie5533 2025-12-3021:554 reply

        What do you use for feature flags?

        • By emptysea 2025-12-3022:172 reply

          Not OP, but I think building feature flags yourself really isn’t hard and worth doing. It’s such an important component that I wouldn’t want to depend on a third party

          • By abustamam 2025-12-312:06

            I agree, but it's hard to get the nuances right. It's easy to roll out a feature to half of your user base. It's a bit harder to roll a feature out to half of users who are in a certain region, and have the flag be sticky on them.

            We use Unleash at work, which is open source, and it works pretty well.

          • By schrodinger 2025-12-3119:09

            I generally agree, but see some more nuance. I think feature-flagging is an overloaded term that can mean two things.

            First, my philosophy is that long-lived feature branches are bad, and lead to pain and risk once complete and need to be merged.

            Instead, prefer to work in small, incremental PRs that are quickly merged to main but dormant in production. This ensures the team is aware of the developing feature and cannot break your in-progress code (e.g. with a large refactor).

            This usage of "feature flags" is simple enough that it's fine and maybe even preferable to build yourself. It could be as simple as env vars or a config file.

            --

            However, feature flagging may also refer to deploying two variants of completed code for A/B testing or just an incremental rollout. This requires the ability to expose different code paths to selected users and measure the impact.

            This sort of tooling is more difficult to build. It's not impossible, but comparatively complex because it probably needs to be adjustable easily without releases (i.e. requires a persistence layer) and by non-engineers (i.e. requires an admin UI). This becomes a product, and unless it's core to your business, it's probably better to pick something off the shelf.

            Something I learned later in my career is that measuring the impact is actually a separate responsibility. Product metrics should be reported on anyway, and this is merely adding the ability to tag requests or other units of work with the variants applied, and slice your reporting on it. It's probably better not to build this either, unless you have a niche requirement not served by the market.

            --

            These are clearly two use cases, but share the overloaded term "feature flag":

            1. Maintaining unfinished code in `main` without exposing it to users, which is far superior than long-lived feature branches but requires the ability to toggle.

            2. Choosing which completed features to show to users to guide your product development.

            (2) is likely better served by something off the shelf. And although they're orthogonal use cases, sometimes the same tool can support both. But if you only need (1), I wouldn't invest in a complex tool that's designed to support (2)—which I think is where I agree with you :)

        • By catlifeonmars 2025-12-3022:27

          If statements?

        • By adhamsalama 2025-12-3023:07

          Unleash

        • By icar 2025-12-3023:47

          You can also do them in Gitlab.

    • By giancarlostoro 2025-12-3020:453 reply

      I like keeping old branches but a lot of places ditch them, never understood why. I also dislike git squash, it means you have to make a brand new branch for your next PR, waste of time when I should be able to pull down master / dev / main / whatever and merge it into my working branch. I guess this is another reason I prefer the forking approach of github, let devs have their own sandbox and their own branches, and let them get their work done, they will PR when its ready.

      • By sallveburrpi 2025-12-3021:004 reply

        squash results in a cleaner commit history. at least that’s why we mandate it at my work. not everyone feels the same about it I guess

        • By Denvercoder9 2025-12-3021:076 reply

          Squashing only results in a cleaner commit history if you're making a mess of the history on your branches. If you're structuring the commit history on your branches logically, squashing just throws information away.

          • By literallyroy 2025-12-3022:193 reply

            I’m all ears for a better approach because squashing seems like a good way to preserve only useful information.

            My history ends up being: - add feature x - linting - add e2e tests - formatting - additional comments for feature - fix broken test (ci caught this) - update README for new feature - linting

            With a squash it can boil down to just “added feature x” with smaller changes inside the description.

            • By Denvercoder9 2025-12-3023:021 reply

              If my change is small enough that it can be treated as one logical unit, that will be reviewed, merged and (hopefully not) reverted as one unit, all these followup commits will be amends into the original commit. There's nothing wrong with small changes containing just one commit; even if the work wasn't written or committed at one time.

              Where logical commits (also called atomic commits) really shine is when you're making multiple logically distinct changes that depend on each other. E.g. "convert subsystem A to use api Y instead of deprecated api X", "remove now-unused api X", "implement feature B in api Y", "expose feature B in subsystem A". Now they can be reviewed independently, and if feature B turns out to need more work, the first commits can be merged independently (or if that's discovered after it's already merged, the last commits can be reverted independently).

              If after creating (or pushing) this sequence of commits, I need to fix linting/formatting/CI, I'll put the fixes in a fixup commit for the appropriate and meld them using a rebase. Takes about 30s to do manually, and can be automated using tools like git-absorb. However, in reality I don't need to do this often: the breakdown of bigger tasks into logical chunks is something I already do, as it helps me to stay focused, and I add tests and run linting/formatting/etc before I commit.

              And yes, more or less the same result can be achieved by creating multiple MRs and using squashing; but usually that's a much worse experience.

              • By literallyroy 2026-01-1320:41

                Thanks for the reply :]

                That seems better as long as you can keep it standard across the team. I don’t usually check each commit when reviewing since frequent iterative commits mean folks change their mind and I’d review already removed logic when looking at early commits.

                I’ve been scraping by on basic git usage so didn’t know about fix-up commits, that’s excellent.

            • By WorldMaker 2025-12-3115:48

              You can always take advantage of the graph structure itself. With `--first-parent` git log just shows your integration points (top level merge commits, PR merges with `--no-ff`) like `Added feature X`. `--first-parent` applies to blame, bisect, and other commands as well. When you "need" or most want linear history you have `--first-parent` and when you need the details "inside" a previous integration you can still get to them. You can preserve all information and yet focus only on the top-level information by default.

              It's just too bad not enough graphical UIs default to `--first-parent` and a drill-down like approach over cluttered "subway graphs".

            • By mh2266 2025-12-311:17

              stacked diffs are the best approach and working at a company that uses them and reading about the "pull request" workflow that everyone else subjects themselves to makes me wonder why everyone is not using stacked diffs instead of repeating this "squash vs. not squash" debate eternally.

              every commit is reviewed individually. every commit must have a meaningful message, no "wip fix whatever" nonsense. every commit must pass CI. every commit is pushed to master in order.

          • By TheGRS 2025-12-3021:382 reply

            Not everyone develops and commits the same way and mandating squashing is a much simpler management task than training up everyone to commit in a similar manner.

            • By esafak 2025-12-3021:571 reply

              Besides, they probably shouldn't make PR commits atomic, but do so as often as needed. It's a good way to avoid losing work. This is in tension with leaving behind clean commits, and squashing resolves it.

              • By gbear605 2025-12-3022:43

                The solution there is to make your commit history clean by rebasing it. I often end my day with a “partial changes done” commit and then the next day I’ll rebase it into several commits, or merge some of the changes into earlier commits.

                Even if we squash it into main later, it’s helpful for reviewing.

            • By sallveburrpi 2025-12-3022:34

              We also do conventional commits: https://www.conventionalcommits.org/

              Other than that pretty free how you write commit messages

          • By bb88 2025-12-3023:08

            At work there was only one way to test a feature, and that was to deploy it to our dev environment. The only way to deploy to dev was to check the repo into a branch, and deploy from that branch.

            So one branch had 40x "Deploy to Dev" commits. And those got merged straight into the repo.

            They added no information.

          • By eddd-ddde 2025-12-317:04

            What you really need is stacked changes, where each commit is reviewed, ran on ci, and merged independently.

            No information loss, and every commit is valid on their own, so cherry picks maintain the same level of quality.

          • By trevor-e 2025-12-3021:472 reply

            Good luck getting 100+ devs to all use the same logical commit style. And if tests fail in CI you get the inevitable "fix tests" commit in the branch, which now spams your main branch more than the meaningful changes. You could rebase the history by hand, but what's the point? You'd have to force push anyway. Squashing is the only practical method of clean history for large orgs.

            • By mattbillenstein 2025-12-3022:332 reply

              This - even 5 devs.

              Also rebasing is just so fraught with potential errors - every month or two, the devs who were rebasing would screw up some feature branch that they had work on they needed and would look to me to fix it for some reason. Such a time sink for so little benefit.

              I eventually banned rebasing, force pushes, and mandated squash merges to main - and we magically stopped having any of these problems.

              • By William_BB 2025-12-3022:481 reply

                We squash, but still rebase. For us, this works quite well. As you said, rebasing needs to be done carefully... But the main history does look nice this way.

                • By mattbillenstein 2025-12-312:30

                  Why bother with the rebase if you squash anyway? That history just gets destroyed?

              • By esafak 2025-12-3022:47

                Rebase before creating PR, merge after creating PR.

            • By Denvercoder9 2025-12-3023:04

              > Good luck getting 100+ devs to all use the same logical commit style

              The Linux kernel manages to do it for 1000+ devs.

          • By mmh0000 2025-12-3021:401 reply

            True but. There's a huge trade-off in time management.

            I can spend hours OCDing over my git branch commit history.

            -or-

            I can spend those hours getting actual work done and squash at the end to clean up the disaster of commits I made along the way so I could easily roll back when needed.

            • By tedmiston 2025-12-3021:441 reply

              it's also very easy to rewrite commit history in a few seconds.

              • By mmh0000 2025-12-3021:521 reply

                If I'm rewriting history ... why not just squash?

                But also, rewriting history only works if you haven't pushed code and are working as a solo developer.

                It doesn't work when the team is working on a feature in a branch and we need to be pushing to run and test deployment via pipelines.

                • By 9029 2025-12-3023:13

                  > But also, rewriting history only works if you haven't pushed code and are working as a solo developer.

                  Weird, works fine in our team. Force with lease allows me to push again and the most common type of branch is per-dev and short lived.

        • By awesome_dude 2025-12-3023:01

          Squash loses the commit history - all you end up with is merge merge merge

          It's harder to debug as well (this 3000line commit has a change causing the bug... best of luck finding it AND why it was changed that way in the first place.

          I, myself, prefer that people tidy up their branches such that their commits are clear on intent, and then rebase into main, with a merge commit at the tip (meaning that you can see the commits AND where the PR began/ended.

          git bisect is a tonne easier when you have that

        • By Faaak 2025-12-3021:081 reply

          What about separate, atomic, commits? Are they squashed too? Makes reverting a fix harder without impacting the rest, no?

          • By ezfe 2025-12-3021:38

            PRs should be atomic, if they need to be separated for reverting, they should be multiple PRs.

        • By UltraSane 2025-12-3022:173 reply

          "squash results in a cleaner commit history" Isn't the commit history supposed to be the history of actual commits? I have never understood why people put so much effort into falsifying git commit histories.

          • By alemanek 2025-12-3022:481 reply

            Here is how I think of it. When I am actively developing a feature I commit a lot. I like the granularity at that stage and typically it is for an audience of 1 (me). I push these commits up in my feature branch as a sort of backup. At this stage it is really just whatever works for your process.

            When I am ready to make my PR I delete my remote feature branch and then squash the commits. I can use all my granular commit comments to write a nice verbose comment for that squashed commit. Rarely I will have more than one commit if a user story was bigger than it should be. Usually this happens when more necessary work is discovered. At this stage each larger squashed commit is a fully complete change.

            The audience for these commits is everyone who comes after me to look at this code. They aren’t interested in seeing it took me 10 commits to fix a test that only fails in a GitHub action runner. They want the final change with a descriptive commit description. Also if they need to port this change to an earlier release as a hotfix they know there is a single commit to cherry pick to bring in that change. They don’t need to go through that dev commit history to track it all down.

            • By UltraSane 2025-12-3023:47

              The "cleaner" commit history should be a separate layer and the actual commit history should never be altered.

          • By catlifeonmars 2025-12-3022:35

            “Falsifying” is complete hyperbole. Git commit history is a tool and not everyone derives the same ROI from the effort of preserving it. Also squashing is pretty effortless.

          • By jtafurth 2025-12-3023:481 reply

            There are several valid reasons to "falsify" commit history.

            - You need to remove trash commits that appear when you need to rerun CI. - You need to remove commits with that extra change you forgot. - You want to perform any other kind of rebase to clean up messages.

            I assume in this thread some people mean squashing from the perspective of a system like Gitlab where it's done automatically, but for me squashing can mean simply running an interactive (or fixup) and leaving only important commits that provide meaningful information to the target branch.

            • By awesome_dude 2025-12-310:53

              > You need to remove trash commits that appear when you need to rerun CI

              Serious question, what's going on here?

              Are you using a "trash commit" to trigger your CI?

              Is your CI creating "trash commits" (because build artefacts)?

      • By eddd-ddde 2025-12-3020:491 reply

        I'm very fortunate to not have to use PR style forges at work (branch based, that is). Instead each commit is its own unit of code to review, test, and merge individually. I never touch branches anymore since I also use JJ locally.

      • By normie3000 2025-12-3022:19

        > you have to make a brand new branch for your next PR

        Is there overhead to creating a branch?

  • By sethammons 2025-12-3020:4510 reply

    people talk about "one change, everywhere, all at once." That is a great way to break production on any api change. if you have a db and >2 nodes, you will have the old system using the old schema and the new system using the new schema unless you design for forwards-backwards compatible changes. While more obvious with a db schema, it is true for any networked api.

    At some point, you will have many teams. And one of them _will not_ be able to validate and accept some upgrade. Maybe a regression causes something only they use to break. Now the entire org is held hostage by the version needs of one team. Yes, this happens at slightly larger orgs. I've seen it many times.

    And since you have to design your changes to be backwards compatible already, why not leverage a gradual roll out?

    Do you update your app lock-step when AWS updates something? Or when your email service provider expands their API? No, of course not. And you don't have to lock yourself to other teams in your org for the same reason.

    Monorepos are hotbeds of cross contamination and reaching beyond API boundaries. Having all the context for AI in one place is hard to beat though.

    • By mjr00 2025-12-3021:171 reply

      100%, this is all true and something you have to tackle eventually. Companies like this one (Kasava) can get away with it because, well, they likely don't have very many customers and it doesn't really matter. But when you're operating at a scale where you have international customers relying on your SaaS product 24/7, suddenly deploys having a few minutes of downtime matters.

      This isn't to say monorepo is bad, though, but they're clearly naive about some things;

      > No sync issues. No "wait, which repo has the current pricing?" No deploy coordination across three teams. Just one change, everywhere, instantly.

      It's literally impossible to deploy "one change" simultaneously, even with the simplest n-tier architecture. As you mention, a DB schema is a great example. You physically cannot change a database schema and application code at the exact same time. You either have to ensure backwards compatibility or accept that there will be an outage while old application code runs against a new database, or vice-versa. And the latter works exactly up until an incident where your automated DB migration fails due to unexpected data in production, breaking the deployed code and causing a panic as on-call engineers try to determine whether to fix the migration or roll back the application code to fix the site.

      To be a lot more cynical; this is clearly an AI-generated blog post by a fly-by-night OpenAI-wrapper company and I suspect they have few paying customers, if any, and they probably won't exist in 12 months. And when you have few paying customers, any engineering paradigm works, because it simply does not matter.

      • By eptcyka 2026-01-0210:00

        The only way to do a sane migration without downtime is to have tha application handle both schema versions at the same time. This is easily doable with a monorepo.

    • By kccqzy 2025-12-3020:552 reply

      I’m not sure why you made the logical leap from having all code stored in a single repo to updating/deploying code in lockstep. Where you put your code (the repo) can and should be decoupled from how you deploy changes.

      > you will have the old system using the old schema and the new system using the new schema unless you design for forwards-backwards compatible changes

      Of course you design changes to be backwards compatible. Even if you have a single node and have no networked APIs. Because what if you need to rollback?

      > Maybe a regression causes something only they use to break. Now the entire org is held hostage by the version needs of one team.

      This is an organizational issue not a tech issue. Who gives that one team the power to hold back large changes that benefit the entire org? You need a competent director or lead to say no to this kind of hostage situation. You need defined policies that balance the needs of any individual team versus the entire org. You need to talk and find a mutually accepted middle ground between teams that want new features and teams that want stability and no regressions.

      • By ajanuary 2025-12-3021:331 reply

        The point is that the realities of not being able to deploy in lockstep erode away at a lot of the claimed benefits the monorepo gives you in being able to make a change everywhere at once.

        If my code has to be backwards compatible to survive the deployment, then having the code in two different repos isn’t such a big deal, because it’ll all keep working while I update the consumer code.

        • By valicord 2025-12-3022:141 reply

          The point is atomic code changes, not atomic deployments. If I want to rename some common library function, it's just a single search and replace operation in a monorepo. How do you do this with multiple repos?

          • By mjr00 2025-12-3022:182 reply

            > If I want to rename some common library function, it's just a single search and replace operation in a monorepo. How do you do this with multiple repos?

            Multiple repos shouldn't depend on a single shared library that needs to be updated in lockstep. If they do, something has gone horribly wrong.

            • By array_key_first 2025-12-3120:461 reply

              They do, it's just instead of it being a library call it's a network call usually, which is even worse. Makes it nigh impossible to refactor your codebase in any meaningful way.

              • By suralind 2025-12-3121:381 reply

                But if you need to rename endpoint for example you need to route service A version Y to compatible version in service B. After changing the endpoint, now you need to route service A version Z to a new version of service B. Am I missing something? Meaning that it doesn’t truly mater whether you have 1 repo, 2 repos or 10 repos. Deployments MUST be done in sequence and there MUST be a backwards compatible commit in between OR you must have some mesh that’s going to take care of rerouting requests for you.

                • By array_key_first 2025-12-3122:431 reply

                  You just deploy all the services at once, A B style. Just flip to the new services once they're all deployed and make the old ones inactive, in one go. Yes you'll probably need a somewhat central router, maybe you do this per-client or per-user or whatever makes sense.

                  • By suralind 2026-01-0115:261 reply

                    So that's blue green with added version aware routing. What if you need to rollback? Good luck I guess.

                    • By array_key_first 2026-01-0116:41

                      You can do phased deployments with blue green, that's what we do. It depends on your application but ours has a natural segmentation by client. And when you roll back you just flip the active and passive again.

            • By valicord 2025-12-317:50

              It doesn't need to, it's just much more convenient when you can do everything in a single commit.

      • By catlifeonmars 2025-12-3022:49

        > This is an organizational issue not a tech issue.

        It’s both. Furthermore, you _can_ solve organizational problems with tech. (Personally, I prefer solutions to problems that do not rely strictly on human competence)

    • By gnarlouse 2025-12-3021:431 reply

      I think I disagree.

      We have a monorepo, we use automated code generation (openapi-generator) for API clients for each service derived from an OpenAPI.json generated by the server framework. Service client changes cascade instantly. We have a custom CI job that trawls git and figures out which projects changed (including dependencies) as to compute which services need to be rebuilt/redeployed. We may just not be at scale—thank God. We're a small team.

      • By mjr00 2025-12-3022:27

        Monorepo vs multiple repos isn't really relevant here, though. It's all about how many independently deployed artifacts you have. e.g. a very simple modern SaaS app has a database, backend servers and some kind of frontend that calls the backend servers via API. These three things are all deployed independently in different physical places, which means when you deploy version N, there will be some amount of time they are interacting with version N-1 of the other components. So you either have to have a way of managing compatibility, or you accept potential downtime. It's just a physical reality of distributed systems.

        > We may just not be at scale—thank God. We a small team.

        It's perfectly acceptable for newer companies and small teams to not solve these problems. If you don't have customers who care that your website might go down for a few minutes during a deploy, take advantage of that while you can. I'm not saying that out of arrogance or belittlement or anything; zero-downtime deployments and maintaining backwards compatibility have an engineering cost, and if you don't have to pay that cost, then don't! But you should at least be cognizant that it's an engineering decision you're explicitly making.

    • By catlifeonmars 2025-12-3022:431 reply

      > Having all the context for AI in one place is hard to beat though.

      Seems like a weird workaround, you could just clone multiple repos into a workspace. Agree with all your other points though.

      • By scubbo 2025-12-3022:59

        Exactly. Monorepo-enjoyers like to pretend that workspaces don't a) exist, and b) provide >90% of the benefits of a monorepo, with none of the drawbacks.

    • By nosefrog 2025-12-3023:20

      > At some point, you will have many teams. And one of them _will not_ be able to validate and accept some upgrade. Maybe a regression causes something only they use to break. Now the entire org is held hostage by the version needs of one team. Yes, this happens at slightly larger orgs. I've seen it many times.

      The alternative of every service being on their own version of libraries and never updating is worse.

    • By Groxx 2025-12-3022:02

      atomic updates in particular is one of those things that sounds good to the C-suite, but falls apart extremely badly in the lower levels.

      months-long delays on important updates due to some large project doing extremely bad things and pushing off a minor refactor endlessly has been the norm for me. but they're big so they wield a lot of political power so they get away with it every time.

      or worse, as a library owner: spending INCREDIBLE amounts of time making sure a very minor change is safe, because you can't gradually roll it out to low-risk early adopter teams unless it's feature-flagged to hell and back. and if you missed something, roll back, write a report and say "oops" with far too many words in several meetings, spend a couple weeks triple checking feature flagging actually works like everyone thought (it does not, for at least 27 teams using your project), and then try again. while everyone else working on it is also stuck behind that queue.

      monorepos suck imo. they're mostly company lock-in, because they teach most absolutely no skills they'd need in another job (or for contributing to open source - it's a brain drain on the ecosystem), and all external skill is useless because every monorepo is a fractal snowflake of garbage.

    • By jeffbee 2025-12-3021:39

      I really have never been able to grasp how people who believe that forward-compatible data schema changes are daunting can ever survive contact with the industry at scale. It's extremely simple to not have this problem. "design for forwards-backwards compatible changes" is what every grown-up adult programmer does.

    • By Alconicon 2025-12-3023:05

      You always have this problem thats why you have a release process for apis.

      And monorepo or not, bad software developers will always run into this issue. Most software will not have 'many teams'. Most software is written by a lot of small companies doing niche things. Big software companies with more than one team, normally have release managers.

      My tipp: use architecture unit tests for external facing APIs. If you are a smaller company: 24/7 doesn't has to be the thing, just communicate this to your customers but overall if you run SaaS Software and still don't know how to do zero-downtime-deployment in 2025/2026, just do whatever you are still doing because man come on...

HackerNews