A multi-service application separates one product into several deployable processes that cooperate over network boundaries. On an App Platform, those processes can include:
- public web services;
- internal APIs;
- background workers;
- scheduled jobs;
- databases;
- object storage;
- persistent volumes.
The architecture is useful when different parts of the workload need independent deployment, scaling, credentials, or failure isolation.
Raff Technologies Apps supports multi-service applications, private service-to-service communication, managed database bindings, workers, cron jobs, one-off jobs, persistent volumes, custom domains, and Docker Compose imports.
Start from process boundaries, not microservice fashion
A multi-service application does not need to be a microservices architecture.
A small team might run:
web api worker database
inside one product.
The important question is whether each process has a distinct operational role.
Split a service when it needs:
- different scaling;
- different credentials;
- different runtime;
- different release cadence;
- different availability behavior;
- isolation from another workload.
Do not split services merely to increase architectural complexity.
Public and private services have different boundaries
A public web service may receive internet traffic.
An internal worker or API often should not.
A useful topology is:
Internet ↓ public web/API ↓ private service network worker / internal API ↓ managed database
Keep internal services private unless a real public entry point is required.
Service-to-service communication should use stable names
Avoid coupling services to disposable IP addresses.
Use platform-provided internal service discovery or stable hostnames where available.
The application should be able to tolerate:
- instance replacement;
- rolling deployment;
- horizontal scaling.
Hard-coded instance IPs make those workflows fragile.
Bind databases per service
Different services may need different data privileges.
For example:
web → read/write app tables worker → read/write queue/job tables reporting → read-only access
Do not share an administrative database credential across the whole application when scoped credentials are possible.
Workers belong outside the request path
Background work such as:
- email delivery;
- image processing;
- report generation;
- webhook retry;
- large imports;
should usually run in a worker process rather than blocking public HTTP requests.
Use Background Workers and Task Queues for SaaS Apps for queue semantics and retry design.
Scheduled jobs are a separate execution model
A cron/scheduled process runs because of time, not incoming HTTP traffic.
Examples:
- nightly reconciliation;
- cleanup;
- reports;
- billing;
- backup coordination.
Keep scheduled work separate from the public web process when failure or resource behavior differs.
Persistent data should live outside disposable runtimes
Application service instances should normally be replaceable.
Persistent state belongs in:
- managed databases;
- object storage;
- persistent volumes.
Do not rely on a container or runtime filesystem for important user data unless the platform explicitly provides persistent storage mounted for that purpose.
Custom domains belong at the public edge
Only services intended for public traffic need custom domains.
An application may have:
app.example.com → web api.example.com → API worker → private only database → private only
This keeps the public surface small.
Multi-service deployments need dependency awareness
Deploying one service can affect another.
Examples:
- API response shape changes;
- queue payload format changes;
- database schema changes;
- shared environment variable changes.
Use backward-compatible changes where multiple service versions may coexist.
Scale services independently when workloads differ
A public API and a background worker rarely scale for the same reason.
The API might need more instances for request traffic.
The worker might need more concurrency because queue depth grows.
Independent service scaling is one of the main reasons to split workloads on an App Platform.
Docker Compose can accelerate migration
If the application already uses Docker Compose, importing the topology can reduce initial migration work.
Still review:
- which services should be public;
- which stateful services should move to managed products;
- secrets;
- volumes;
- health checks;
- scaling.
Do not assume the local Compose topology is the ideal production topology.
Multi-service checklist
Before production:
- every service has a clear role;
- public/private exposure is intentional;
- secrets are scoped;
- data dependencies are explicit;
- workers are separated where needed;
- scheduled jobs are isolated;
- persistent state is externalized;
- health checks exist;
- service-to-service compatibility is considered;
- scaling can be changed independently.
Frequently asked questions
Is a multi-service app the same as microservices?
No. A multi-service application can remain one product or codebase while using separate deployable processes for web, API, workers, and scheduled jobs.
Should every service have a public URL?
No. Internal workers and private APIs should remain private when they do not need direct internet traffic.
Can different services scale independently?
Yes. Independent scaling is one of the main benefits of separating services.
Where should persistent data live?
Use managed databases, object storage, or persistent volumes instead of relying on disposable runtime filesystems.
Can Docker Compose be used for App Platform migration?
Yes when supported, but review the imported topology rather than assuming the local Compose model is optimal for production.