This is a difficult topic. Like everything in IT is complex and it depends. Organizing teams and environments are especially difficult as there are many factors/variables to consider: project size, project type, project stage, and so on. There is no single best solution, and the solution should be verified overtime against the goal.
How to start? First, you need to define the goal (s). Most often it is productivity/ performance and/or problem-solving. Then define the constraints. They are important because they filter possible solutions:

Constraints
Let’s look at the important constraints:
- inflexibility of the organization
This is a common problem in larger organizations. They want an agile way of working, but it takes years to change their culture and organizational flexibility. Microservices are a very demanding environment that requires a lot of communication, team collaboration, and even moving people between teams to deliver common functions. Decisions need to be made very quickly to avoid major problems and consequences. Building microservices for an organization that is not flexible enough and couldn’t adapt quickly to changes is a recipe for a disaster.
- cognitive load
Cognitive load is the total amount of mental effort used in working memory. The ability, or rather a limitation, to capture large amounts of information at once. The cognitive load is high when there is time pressure, no documentation and everyone is constantly discovering the requirements, bad code architecture – you look at the code of the project or services and do not know what it is about (what are the responsibilities/contract, implemented functions, etc.), no handy tools, e.g., log aggregation, fully automated pipelines, tests and so on.
I think there is one more aspect. Amount of domain/business knowledge. In large projects, the number of requirements is huge. Every day developers implement many of them. Code and processes are constantly changing. There is no way to cope with domain learning unless we break it down into smaller, more consistent parts like subdomains. You can read more here: Negative consequences of large amount of information in IT project
- other important constraints organisation and project specific
Security, regulations, delivery road map, specific requirements, time/business pressure etc. Everything what is important from organisation and project view.
Solutions
The main principle: think of the team as the unit that delivers the (business) functionality. To achieve that “Each team that owns one or more services must be autonomous. A team must be able to develop and deploy their services with minimal collaboration with other teams.”
Let’s look at the solutions, their advantages, disadvantages and consequences:
- team per product/application
The most common pattern is that team are responsible for autonomous/independent module(s): products, applications, and services. By module autonomy we achieve team autonomy, because team don’t need to collaborate or communicate with other teams, or at least not very often. The problem is that it is very difficult to achieve autonomy.
In case of products and applications the autonomy is possible:

At the beginning of a project, in order to deliver applications/products very quickly, teams build some common platform/services. Later in the project, more and more requirements appear and cause more and more dependencies. A big problem:

Here we have case study Microservices: Organizing Large Teams for Rapid Delivery where teams started building products on shared services and encountered many dependency issues, and eventually moved to independent products or even code bases. It is a great example showing that dependencies are so painful that it pays to refactor solutions and build a new codebase instead of constantly solving dependencies problems and fighting other teams 🙂
Advantages
Business independence of the products – each of the products can be developed independently! Team independence – each team decides about its product roadmap.
Disadvantages
The difficult flow of knowledge and technical solutions. This can be a problem for specific companies, such as banks, that have a regulated environment and each team solves the same problems. Solution – a technical guild or common repository of libraries and best practices.
Variety of languages, frameworks, solutions in different projects. Solution – the architect or technical LCoE has to ensure homogeneity of the solutions.
In the case of microservices that are part of a larger solution, it is difficult to achieve independence because the real value of microservices is collaboration.
- service per team
There is a microservices pattern Service per team (microservices.io) “Each service is owned by a team, which has sole responsibility for making changes. Ideally each team has only one service”. In practice there are more services than teams, so we have something like this:

Important aspects to consider:
- complexity of the service – some services are simple and some are complex, therefore the complexity should be evenly distributed among the teams
- service stability – some services change very often, while others are stable, therefore the ‘changes’ should be evenly distributed
- future changes/requirements – which services will change in the near future and in the long term, so we can evenly distribute the work. This is a very important point as the team can put more effort, e.g., refactoring, on a service that will change a lot
- dependencies between teams’ services – microservices work together to provide functionality/business value. Microservices communication forces teams to communicate, and microservices dependency forces team dependency.

Team’s A services depends on two services of team B, teams B services depends on one service of team A. Please visualize the dependencies on the diagram and discuss. Extreme cases where one team services depend on many others, or many teams depend on one team services should be eliminated (presented simplified without services):

In well-designed services, the amount of communication is small, which is good. In poorly designed services, the amount of communication is large and forces communication/cooperation between teams, which is a very difficult situation in the context of team organization.
Few words about autonomy. If the autonomy of services is good, the teams can communicate by contract. If the autonomy of services is low, contract is not clear, many communications, so we have to communicate with people directly.
Advantages
The teams are responsible for the services. This is a very important psychological effect as developers care more about their properties / services. They put more effort into making their services “best”.
Teams specialize in their own services – code and business knowledge, thanks to which they can make changes / implement new functions quickly and easily.
If the services are properly designed – they are autonomous, the service with new business functions can be released independently.
Disadvantages
Not properly designed services have many dependencies, and the functions or stories need to be implemented in many services, including services owned by other teams, so there are team dependencies. Solution? Company should develop an effective model of team cooperation. This is a real challenge for inflexible organizations.
You see and feel that ‘service per team’ requires a lot of analysis to do it properly, there is team dependency problem and autonomy is very important, so maybe it is a better solution? Yes, it is:
- subdomain per team
A subdomain (What is subdomain?) is a broad area of business functions, but they relate to each other, so a subdomain is a cohesive autonomous area. This autonomy is the main reason why microservices are built for a subdomain, especially at the beginning of a project Well-designed system starts with domains. There is also the Decompose by subdomain (microservices.io) microservices pattern which confirms that subdomains are stable and cohesive, so creating a microservice for a subdomain has many advantages

During the project, the service is broken down into smaller parts, taking into account bounded contexts, aggregates or technical aspects such as scaling, resources and security. The beauty is that split microservices (most often) are located in the subdomain area

Your project can have more subdomains than teams, so use the complexity, stability, and future changes aspects outlined above to assign subdomains to teams appropriately. Dependencies are unlikely to be a problem as a subdomain contains features/part of a process that is independent.
Advantages
Ownership of subdomains/related services – developers take care of their backyard.
Stories or even features implemented within subdomain services – no team dependencies or very small number of dependencies.
Subdomains are part of the process e.g. selling process include subdomains: ordering, payment, delivery, so we know where to look for problems.
Disadvantages
Subdomain is an abstract concept, so it is difficult for developers to understand.
In existing microservices project subdomains must be discovered and services that have responsibilities from multiple subdomains must be refactored to match the domain (investment that pays back very quickly):

- feature per team

Advantages
The team is responsible for the entire feature – e2e client functionality. This is a huge advantage as there is no dependency/collaboration between teams which always causes a lot of problems.
Disadvantages
Each team should understand almost the entire system, but most often teams implement features that relate to the services they know best.
Microservices have no owner. No responsibility for services. …
This solution is only possible when the cognitive load/knowledge amount is not high, I would say is low. When the project/solution is complex and the quality is low, lack of documentation, bad code architecture, etc., such a solution causes a lot of pain.
Here is the great presentation Microservices and teams organization by Viktor Grgić
What to choose
It’s a tough decision. To clarify the decision look at the diagram:

If the project is not large and the complexity is not high, you can choose “feature per team”. Remember, however, that it is important to keep complexity (technical debt) low.
I think subdomains are always a good option, even if we have “feature per team” or “service per team”. It is good practice to discover subdomains and divide the problem space into coherent areas.
If the project is very large and the complexity is high, I think it is a good idea to choose “service by team”. We further divide the problem area into smaller, specialized areas, e.g. customer credibility assessment may consist of a basic and more extensive process. They can be two different subdomains. Of course, we also take into account the solution, i.e. technical issues such as scalability, availability, efficiency, resource consumption, security, etc.