In early 2021, Filestage raised a €2.8 million Series A. We started hiring engineers in early summer. Over the following nine months, the development department grew from six engineers to twenty-two people.

At six engineers, one team worked well. We knew which features everyone was changing, where conflicts might appear, and who held the context needed to fix a production issue. This setup relied on everyone keeping most of the product in their head, but this wouldn't scale.

My goal was to apply an approach that had already worked at other companies, mainly Amazon's two-pizza team model: small, autonomous teams with single-threaded ownership of a customer problem. I wanted several teams that could make progress independently, while preserving the speed we had when we were six.

The model that worked for us was simple: define the product domains, assign a squad to each customer outcome, mirror those boundaries in the code, and build enough technical safety for teams to deploy without waiting on me. We scaled ownership, not coordination.

Start with the product, not an org chart

I was a Tech Lead at the time, while our CTO led the department. Before proposing a team structure, I mapped the product using ideas from Domain-Driven Design. I compared several ways of dividing the code: technical layers, frontend and backend, entities, user types, and business domains.

In my experience, technical layers are the default, but they make a poor team boundary. Nearly every customer feature required frontend and backend work, so separate teams would create a handoff for almost every change. Organizing around database entities had a similar problem: one user workflow often crossed several entities, while large entities accumulated unrelated behavior over time.

Product domains gave us a better unit of ownership and autonomy. Our initial map separated the product into:

Domain map classifying Review Workflow and File Commenting as core; Notifications, Demo Content, User, Subscriptions, Daily Digest, Team, Public API, and Customer Support as supporting; and Billing, Authentication, File Storage, Transcoding, Analytics, Logger, Mail, Internationalization, and Permissions as generic
Our initial Domain-Driven Design map grouped product capabilities into core, supporting, and generic domains

This was not yet an organization design. It was a way to understand what changed together, what language our customers used, and which knowledge an engineer needed to work safely. Only then did we turn the domains into teams.

Define squads around customer jobs

I brought the domain map and the popular Scaling Agile at Spotify article to the CTO and CPO. The word squad was useful because it described the small, cross-functional, autonomous teams we wanted. We took what made sense and adapted it to our context. Even the original Spotify article describes its model as a snapshot of an evolving company, not a finished framework.

The CPO and I created a document that remains our source of truth today. For every squad it names a primary persona, the job that person is trying to do, a summary of the squad's purpose, a detailed feature list, and the people responsible. Those fields made an abstract structure operational.

We started with three squads:

Integrations began with only one engineer. Later, it became more strategically important, so we hired two more engineers and grew it into a fourth squad.

The feature list kept ownership crystal clear. Customer Support could select the affected feature from a dropdown, and tickets were automatically routed to the correct squad. Other departments could look up the PM or Engineering Manager instead of asking around in Slack.

Draw boundaries with clear contracts

Workflow, Feedback, and Integrations boundaries were clear because much of their work lived on different product pages. Supporting was harder. It risked becoming the squad responsible for everything that did not fit elsewhere.

We resolved that ambiguity by separating the reusable mechanism from the product behavior:

Supporting owned the reusable capabilities, but the core product squads owned the customer outcomes. This preserved the core squads' autonomy.

We also never prohibited one squad from changing another squad's code. Hard barriers would have replaced coordination with waiting. Engineers could make the change themselves, but the relevant code owners reviewed it. That kept work moving without letting domain decisions drift.

Make the code match the organization

We gradually moved feature code until the directory structure reflected the squad structure, updating imports as we went. Then we added code owners for each area. When someone opened a pull request, the people with the right domain context were automatically asked to review it.

We kept the application as a monolith. We had experimented with microservices before and had already felt the operational and development complexity they introduced. Twenty-two people did not justify turning every team boundary into a network boundary. A well-structured monolith with explicit ownership gave us most of the organizational benefit without distributed-system overhead.

Squad autonomy did not mean four ways of solving the same technical problem. We wanted one frontend framework, consistent data-loading and caching patterns, and clear backend helpers for common operations such as database access. Representatives met around the pillars of operational excellence, reliability, performance, security, and cost, following the AWS Well-Architected Framework.

We created technical chapters across the squad structure for backend, frontend, and infrastructure. Engineers who were more interested in technical topics had the opportunity to become Tech Leads. They defined shared best practices and kept each technical layer moving in one direction, independent of which squad was changing it.

Engineering organization with four vertical product squads intersected by Product, Engineering Manager, Software Engineer, and Tech Lead chapter responsibilities
Product squads owned customer outcomes while chapters aligned technical practices across backend, frontend, and infrastructure

That was our version of aligned autonomy: squads owned decisions and delivery inside their product domains, while the engineering organization maintained a small set of shared technical paths.

Build the safety rails before you scale

In hindsight, this is where I made the biggest mistake. Under pressure to deliver the Series A roadmap, I continued pushing new features while poor reliability kept us firefighting. The original engineers were already interviewing candidates and coaching new hires. Production incidents pulled them back into the code because the new people did not yet know enough to diagnose the system.

Adding people temporarily made the situation harder: more changes entered a fragile system while the few people who could fix it suffered even more context switching. I knew in my gut that some trade-offs were wrong, but I did not push hard enough to fix the foundation first.

If I repeated the transition, I would prioritize these investments:

  1. Automate deployments. We moved from a manual process that released roughly twice a week to deploying every merged pull request. Every squad could then ship without competing for a release window.
  2. Protect critical behavior with E2E tests. More people touching a legacy codebase means more ways to break behavior they do not know exists. We hired a QA Engineer to expand coverage of the most important customer paths.
  3. Assign code owners. Autonomy still needs a clear review path when a change crosses a domain boundary.

We also hired a DevOps Engineer to define our infrastructure as code and improve the delivery system. This was a key enabler for automated deployments. Infrastructure could no longer live inside my head and an AWS account; clear definitions made deployment changes repeatable and helped us create test environments for different teams. QA and DevOps were specialists serving the wider department, while the squads consisted mainly of full-stack engineers. Our JavaScript stack made it practical for engineers to own a feature end to end and move temporarily between squads when an initiative needed help.

Grow leaders before filling teams

We promoted three engineers into Engineering Manager roles at the start. I chose them mainly for proactiveness and attitude. They were already eager to take responsibility beyond their assigned tickets, and they knew the codebase, the people, and the product direction. Their existing context made them well prepared to onboard new engineers.

At Filestage, Engineering Managers still contribute code and lead technical work by example. Their individual throughput expectations were lower because their main responsibility was helping their engineers succeed, not maximizing their own coding output. Keeping a technical track record helped them earn credibility, but they also had to learn that their job was no longer to personally solve every difficult problem.

I coached them through real situations using ideas from The Making of a Manager, How to Win Friends and Influence People, and Radical Candor. I should have reserved more time for this. The better they became at coaching their teams, the more leverage I had to grow the department. By the end of the transition I had become Head of Engineering, while the CTO also took responsibility for operations.

Roll out the structure gradually

We did not wait until twenty-two people had joined and announce a sudden reorganization. After aligning with the CTO and CPO, we assigned roadmap features to the future squads with the people we already had. During hiring, we matched candidates' interests to the domain where possible. Someone excited about frontend interaction could join Feedback and work on media viewers and annotations. Someone drawn to foundational systems could work on permissions, authentication, or file processing in Supporting.

Each squad had an Engineering Manager and engineers. We shared one Product Manager and one Product Designer between two squads. I explained the transition in an all-hands meeting and spoke directly with the departments most affected. Customer Support needed fast answers, so leaving ownership ambiguous for them would have defeated the point.

The transition took about nine months, mostly because hiring was slow. It was an unusually competitive market, and even hiring remotely around the world required enormous effort. The best technical signal we found was a take-home exercise that resembled the candidate's day-to-day work. We also discussed values and ways of working early, because hiring so many people quickly could easily change the culture by accident.

Coordinate the exceptions, not every task

The squads were autonomous, not isolated. I met weekly with the Engineering Managers to review the roadmap and identify work that might cross boundaries. I held skip-level conversations with engineers to hear what slowed them down. Squads ran their own retrospectives, the whole development team held a monthly retrospective, and I met with the CPO to resolve friction between Engineering and Product.

We started with very little process: Product created one feature concept document, Engineering extended it with a technical concept, colleagues reviewed it, and we shipped. Our feature process became more detailed over the years, but each addition came from friction observed in a retrospective. We did not begin by copying a large checklist into every squad.

Boundaries were stable, but not sacred. We eventually moved SSO from Integrations to Supporting because it fit better with authentication and account administration. Much later, AI Review Agents justified deliberate work across multiple squads so we could move faster. The map served the product; the product did not serve the map.

Measure whether the system is working

I knew the transition was working when three things improved together: total throughput went up, customer-reported defects went down, and team satisfaction stayed high. None of these metrics proves that squads alone caused the result. During the same period we hired people, automated deployments, expanded tests, and improved infrastructure. That is the point: the organization and its technical system had to scale together.

Monthly merged pull requests rising from around 80 in early 2021 to more than 250 in early 2022
Although it may seem natural for output to rise with headcount, it often does not: broken processes and coordination overhead can make a larger team deliver less

Each merged PR represented a production release. The increase showed that growing the team increased finished work instead of collapsing delivery under coordination overhead.

Defect rate chart showing customer-reported bugs per released pull request trending down toward 20 percent
We tracked customer-reported issues over the previous 30 days and compared them with released PRs

Shipping more would not have been a success if customers received more bugs. The later reduction in defect rate gave us confidence that the investments in QA, reliability, and continuous delivery were working. Our satisfaction survey history began after the original transition, so it is not proof of the reorganization, but it showed that the system remained healthy as it matured.

Engineering satisfaction remaining mostly between 85 and 95 percent from 2022 through 2025
Engineering satisfaction remained high in the years after the transition

I explain the metrics and their limitations in more detail in Measure what matters.

When should you split one team?

Six people is not a law, but it has become a useful warning threshold for me. Once a manager has more than six direct reports, it becomes harder to give everyone enough attention. Once more than six engineers regularly change the same product, it becomes harder for each person to understand what everyone else is doing.

Consider splitting when several of these symptoms appear:

If those problems do not exist, keep one team. Squads introduce management and product coordination costs of their own. Creating names and boxes before you have distinct areas of ownership is organization theater.

A practical playbook

  1. Map the product's jobs to be done and the domains that change together.
  2. Give every squad a persona, customer outcome, summary, and explicit feature list.
  3. Define contracts for shared capabilities so an enabling team does not become responsible for every feature using them.
  4. Promote proactive internal leaders early and coach them before their squads fill up.
  5. Automate deployments, protect critical behavior with E2E tests, and assign code owners.
  6. Gradually mirror product ownership in the codebase. Do not assume team boundaries require microservices.
  7. Communicate the map to the whole company and design support-routing and planning workflows around it.
  8. Use a small coordination cadence and add process only when real friction gives you a reason.
  9. Track delivery, quality, and satisfaction together. Optimizing only one will hide the damage done to the others.

Clarity creates autonomy

By the end of those nine months, I was leading a twenty-two-person development department that could build several substantial features in parallel. Cross-squad work still happened, but it was the exception. Most of the time, engineers held a smaller and deeper context, knew why their code would change, and knew exactly whom to ask when they crossed a boundary.

Matrix comparing alignment and autonomy: aligned autonomous teams agree that they need to cross a river while deciding for themselves how to do it
Aligned autonomy: agree on the destination, then let the team decide how to get there

Autonomy is not the absence of alignment. It is what becomes possible when ownership is clear and the foundations are safe enough for people to act on it.

Scaling your engineering team?

I help startup leaders replace firefighting and coordination overhead with clear ownership, reliable delivery, and teams that can ship with confidence.

Book a call Email me