Nucleus, the backend behind this portfolio, is a useful real example for comparing deployment boundaries. It contains Blog, Course, Project, Finance, and other modules inside one Laravel application. The public Next.js website and mobile companion are separate clients, while Nucleus owns persistence and content rules.
This walkthrough uses that existing modular monolith to examine what a service extraction would change. The extraction example is a design exercise, not a claim that Nucleus's invoice or notification modules have already become independently deployed services. No performance improvement or traffic capacity is assumed.
Folders organize code; deployment and ownership define the boundary
A monolith is deployed as one backend application. It can still have well-defined modules, dependency rules, queues, and multiple web or worker processes. In Nucleus, ModulesServiceProvider discovers module routes, migrations, and commands within the same application. Those modules share Laravel's runtime and database authority.
This simplified structure captures the actual organization without suggesting that every internal class is a separate service:
app/Modules/
Blog/
Post/{Controllers, Requests, Repositories, Models, Jobs}
PostCategory/
Course/
Project/
Finance/
Api/
Portfolio/ # published content reads
App/ # authenticated management endpoints
Microservices introduce independently deployable application boundaries. Each service owns its domain behavior and data contract. Other services use an API or events rather than directly writing its tables. A separate physical database server is one possible deployment choice; the important requirement is controlled ownership of data.

Separate applications do not automatically remove coupling. If all services require a coordinated release, share direct database writes, or make long chains of synchronous calls, their operation remains tightly connected. Microsoft's service-boundary guidance uses domain responsibilities, cohesion, consistency needs, and independent deployment to evaluate a split.
Follow one workflow before drawing new boxes
Consider a Nucleus blog edit. Validation checks the category and submitted fields. The repository updates the row and attachment state. An editor-body job can convert embedded images into stored files. Model events queue a webhook that expires the public portfolio's cached content.
The post belongs to a category through a foreign key that uses cascading deletion. Both records are currently managed by one database. Splitting categories into a different service would change that relationship: a remote category lookup cannot behave like an ordinary local foreign key or participate in the same SQL transaction.
Media creates another boundary. A database rollback does not reverse a file upload. Separating storage processing adds network outcomes and retries to that existing problem. Before extracting anything, list the invariants: a public article must have valid content, category changes must follow a deliberate deletion policy, and retries must not attach or delete the wrong files.
Scale a workload before assuming it needs a new service
If editor processing or PDF generation becomes slow, first measure the worker backlog, job duration, query time, and resource usage. A Laravel queue worker can be deployed and scaled separately from HTTP processes while using the same codebase. That changes execution capacity without requiring a new domain API.
Likewise, a modular monolith can run behind a load balancer. Shared session, cache, storage, and job configuration still need care. Microservices make scaling an individual service possible, but each service may bring its own datastore, deployment, monitoring, and incident handling. Independent scaling is a capability to use when a workload justifies it.
There is no reliable “five developers” or “high traffic” threshold that decides this architecture. Ask which workload is constrained and which team can own its full operation. A slow query remains a slow query after moving behind HTTP.
Compare the costs using concrete questions
| Decision | Module in one Laravel application | Independent service |
|---|---|---|
| Changing a domain API | Update callers and implementation in one release. | Support deployed consumers and a compatibility window. |
| Saving related state | Use a local transaction where the data shares a connection. | Define messages, retries, and acceptable intermediate states. |
| Debugging a workflow | Trace local calls and queued jobs. | Correlate requests and messages across deployments. |
| Scaling background work | Add or isolate workers for measured workloads. | Scale the service and account for its dependencies. |
Neither column guarantees faster development or higher availability. A small service with clear ownership may simplify a complex domain. Ten tiny services with unclear responsibility may make a simple change harder. The useful comparison is the cost of the workflow you actually have.
A hypothetical notification-service extraction
Suppose a notification workload needs an independent release cycle and operational owner. An initial contract might accept an event with a stable identity and explicit version. This is illustrative JSON, not an existing Nucleus endpoint:
{
"event_id": "f3a8cdf4-0d42-467b-b186-50edb136cc50",
"event_type": "content.published",
"schema_version": 1,
"content_id": 42,
"occurred_at": "2026-10-11T09:00:00Z"
}The publisher should durably record the event with the content change, then deliver it asynchronously. Otherwise, a process crash between the database commit and the HTTP call can lose the notification. A transactional outbox is one design option; it is additional infrastructure to implement and verify, not a property of ordinary event dispatch.
The consumer needs durable deduplication, bounded retries, and a delivery state. Receiving an event twice must not mean sending the same email twice. A provider timeout may leave the send result uncertain, which requires a deliberate recovery policy. Keep secrets and full recipient data out of broad event payloads.
Define what readers see when the notification service is unavailable. Content publication can succeed while delivery is pending if that is an accepted business rule. If every page request waits for notification service health, the extraction has added an unnecessary availability dependency.
Extract incrementally and keep a rollback path
Start by giving the module a small internal interface and stopping direct cross-module table writes. Add contract tests and observe calls. Then introduce an adapter that can route one workload to either the local implementation or the new service. Migrate a bounded set of operations and compare results before moving ownership.
Do not maintain two uncoordinated writers for the same records. Define when the new service becomes authoritative, how pending work is transferred, and how old consumers remain compatible. A rollback plan must account for data written since the cutover, not just the previous application binary.
For the current Nucleus architecture, modular boundaries, specific query improvements, and reliable queue processing are concrete improvements within the existing deployment. A future extraction should name a measured problem, an independent owner, and a contract that makes the added network boundary worthwhile.



