Software Engineering
Microservices vs Monolith: What We Chose for Our Travel Platform
A real-world comparison of architectural approaches for a growing travel technology company.
4 min readVeetek team
When a travel technology company grows, the architecture question comes up sooner or later. The product has expanded from a booking engine into supplier connections, operations tools and finance. The team has grown. Deployments feel risky. Someone suggests breaking the application into microservices.
We had this discussion as Veetek's platform grew into its current shape: Vee Travel, Vee Connect, Vee Operations and Vee Money. This article explains what we chose and why. Our answer will not suit every team, but the reasoning may help.
What we were trying to solve
It is worth being precise about the problems before choosing a solution. Ours were:
Supplier integrations were slow or unreliable at times, and we did not want one supplier's problems to affect the whole platform.
Some workloads, such as search, needed to scale very differently from others, such as invoicing.
The codebase was growing, and changes in one area sometimes had unexpected effects in another.
We wanted different parts of the team to work with less coordination.
Notably, raw performance of the core application was not the main problem. Most of our slow paths were database queries and external supplier calls, which microservices would not fix on their own.
The case for microservices
Microservices offer independent deployment, independent scaling and strong boundaries between parts of the system. For a travel platform, a supplier integration service is an obvious candidate: it talks to many external APIs, has its own failure patterns and benefits from isolation.
The costs are real, though. Every service boundary becomes a network call that can fail. Data that used to be joined in one query now lives in different databases. A booking that touches inventory, pricing, payment and supplier confirmation becomes a distributed transaction, which needs careful handling with sagas or compensating actions. Operations need service discovery, distributed tracing and more complex deployment pipelines.
For a team of our size, that overhead would have taken time away from the product.
What we chose: a modular monolith with a few separate services
We kept the core platform as a single Laravel application, organised into clear modules that match our products. Each module owns its own models, database tables and services, and other modules interact with it through defined interfaces rather than reaching into its tables directly.
The booking flow, which needs strong consistency across inventory, pricing and payment, stays inside the monolith where database transactions do the work. Holding charter seats, applying an agency markup and debiting a wallet can happen in one transaction, and that is a major advantage.
We separated out a small number of components where the benefits were clear:
Supplier connectors run as isolated workers with their own queues, timeouts and scaling, so a slow GDS or aggregator affects only its own jobs.
Search aggregation scales independently, since it is stateless and bursty.
WebSocket broadcasting runs on its own servers.
These are separate processes and deployments, but they share the same codebase and domain model where it makes sense.
How we keep the monolith healthy
A monolith only stays manageable with discipline. A few practices make the difference:
Module boundaries are enforced with automated architecture tests that fail if one module uses another's internal classes.
Modules communicate through events for side effects, such as sending a confirmation email after a booking, which keeps them loosely coupled.
Feature switches, managed in Vee Operations, let us release changes gradually and turn them off without a deployment.
A good test suite and automated deployments make releasing the monolith routine rather than risky.
This is not a permanent choice. If a module develops very different scaling or release needs, or if a separate team takes full ownership of it, extracting it into its own service becomes easier because the boundary already exists. A well-structured monolith is a good starting point for microservices later. A poorly structured one usually becomes a poorly structured distributed system.
Our advice
Choose architecture based on the problems you have, not the ones larger companies describe. For most travel platforms, a modular monolith with a few isolated services for supplier integrations and search gives most of the benefits with far less operational cost. Invest in clear boundaries first. The deployment model can change later.