From the team behind aidrop.it — one workspace to build, host, and keep changing your code.

A legacy monolith does not become easier to run because somebody turns every folder into a service. Split one part only when it needs to start, fail, scale, release, or receive credentials independently from the rest. Until then, one deployable with a known runtime is safer than a network of new failure modes.

If the operating constraint is still unclear, start with a one-workflow monolith assessment before choosing a component to extract.

A separate folder is not a separate Service

Repositories collect folders for routes, jobs, imports, reports, and helpers. Most still run as one process and change together. Turning each folder into a Service adds an address, a health check, a build, a release record, values, and an ownership boundary. That overhead earns its place only when the component needs its own lifecycle.

Use the first deployment to prove the existing application works as one Service. Then watch for a concrete pressure: a queue consumer blocks web requests, a scheduled report needs different credentials, or the frontend needs releases that should not restart the API. Two apps can share one repository without claiming that every directory is an application.

Split at the operational boundary

Take a report worker as an example. It may use the same repository and database as the web application, but it starts on a schedule, can fail without taking the web path down, and might need an email credential the API never reads. That is a Service boundary you can explain and test.

Create the worker from the same repository only after its entry command, health behaviour, and required values are explicit. Keep one owner for shared database schema changes. A migration that works for the new worker but breaks the older web service has made the split expensive before it delivered any benefit. Keep changes additive until both versions can run during the transition.

Share data deliberately, distribute access narrowly

Two Services may use one database connection, but they should not inherit every project value. List the names each process requires. The web Service may need DATABASE_URL and STRIPE_SECRET_KEY; the worker may need DATABASE_URL and SMTP_PASSWORD. A value used by neither belongs in neither runtime.

This turns review into a simple question: why does this process now need that name? It also gives a legacy team a migration map. Add a value once, move one consumer, restart it, and verify its health. A per-Service value allowlist avoids making a small extraction a project-wide credential change.

Make the second Service earn its keep

Do not split while you only expect a future need. Extract when you can write the operational reason in one sentence and name the check that proves the new boundary works. Build and release the new Service with the old process still intact. Move one request or job to it. Only remove the old path after the new one has evidence behind it.

The resulting architecture remains reversible. Each Service has its own commit-tagged build, and a failed worker release can return to its earlier image without redeploying the web application. Keep the stop rule close: if the same failure repeats after one justified change, report it instead of making the boundary larger. An agent needs stop conditions as much as it needs a build command.

A service-extraction card

Fill this in before creating a second Service. If the first four lines are vague, keep the code in the monolith and collect more evidence.

SERVICE EXTRACTION CARD
Component to extract:
Operational reason: releases / failures / schedule / scale / credentials
What can restart without it:
Repository and branch:
Entry command, port, health path:
Values required by name:
Shared database owner and compatible migration plan:
First traffic or job to move:
Proof of success:
Rollback: image tag, owner, and condition:
Old path removal date and evidence required:

FAQ

When should I split a legacy monolith? Split when a component has an independently testable operational need: it releases on a different rhythm, handles work that must not block requests, needs its own scaling behaviour, or requires credentials unrelated to the rest of the application. Folders alone do not justify the cost.

Can two Services use one repository? Yes. A repository is a source-control boundary, while a Service is a runtime boundary. Keep source together when that helps review, then give each independently running process its own build settings, health check, release record, and address.

Should a worker and web application share every environment variable? No. Share the connection or key only when both processes need the same authority. Record each Service's required names so a new dependency is visible in review and unrelated processes never receive broad access.

How does the platform model this split? On aidrop.it, a Project groups the services, repositories, and backing resources of one product. Each service_build records one Service's repository, branch, runtime settings, and required_secret_names; only the named Project values reach that container, while successful builds remain available by commit tag for a later start or rollback.

Before the next deploy

Get it running from the session you are already in

Connect your coding agent over MCP and ask it to deploy. aidrop builds the repository and runs it on a public address; when a build or the app fails, the log says why, and your agent fixes it and builds again.