Inter-Service Communication¶
When your application has multiple services (e.g., a frontend and a backend), they often need to talk to each other. AppMecca provides a template syntax that automatically resolves service URLs at deploy time, so you never have to hardcode them.
The Problem¶
In a multi-service app, your frontend needs to know the backend's URL. But the URL depends on the app slug, service name, owning group, branch, and environment domain -- things that change between environments and branches. Hardcoding https://myapp-backend-acme.dev.appmecca.net would break the moment you deploy to staging, or on a feature branch.
The Solution: Service Templates¶
In your appmecca.yaml, use template variables in the environment section:
containers:
- name: frontend
dockerfile: frontend/Dockerfile
context: frontend/
- name: backend
dockerfile: backend/Dockerfile
context: backend/
deploy:
- name: frontend
container: frontend
port: 3000
environment:
API_URL: "${service:backend:internal}"
- name: backend
container: backend
port: 8080
health_check:
path: /health
AppMecca replaces the template with the actual address of the backend service when it deploys the container. ${service:backend:internal} becomes a private address inside your app's own network; ${service:backend} becomes the public URL — under path routing an app has ONE hostname and each service is mounted on a path beneath it, so in dev that is https://myapp-acme.dev.appmecca.net/api and in staging https://myapp-acme.staging.appmecca.net/api.
Your frontend code just reads the API_URL environment variable -- no URL construction needed.
Two Types of URLs¶
AppMecca supports two template formats, and which one is correct depends on who reads the value:
- a value a browser reads — anything baked into a client bundle, or set on
a
type: static/type: spaservice — must be the external form; a browser cannot reach the private network. - a value one container uses to call another — an SSR frontend calling its API, a worker calling a service — should be the internal form: it stays inside the private network and never leaves the platform.
External URL (HTTPS, public) — the one to use¶
Resolves to the public HTTPS URL routed through the AppMecca HTTPS router:
On a non-production branch, the branch name is included automatically:
You do not need to change your appmecca.yaml templates -- AppMecca resolves them to the correct branch-scoped URL automatically.
Use this when:
- A browser-based frontend calls a backend API
- A service needs to be reachable from outside the platform
- You want the traffic to go through the platform router (health checks, TLS, routing rules)
Internal URL (HTTP, private)¶
Resolves to a private HTTP address on AppMecca's internal DNS:
The port is the host port AppMecca allocated for the target container, not
the container port you declared in appmecca.yaml.
The address is stable across redeploys
This page used to carry a warning that the internal address went stale whenever the target service was redeployed, because the host port was re-allocated each time. That is no longer true. The port is now frozen as the service's permanent address and the platform forwards it to whichever container is live, so an internal URL baked into your container keeps working across the target's redeploys.
It is not reachable from a browser, and it never will be — that is the point of it. Use the external form for anything a browser loads.
Template Reference¶
| Template | Resolves To | Notes |
|---|---|---|
${service:backend} |
https://myapp-acme.dev.appmecca.net/api |
Public HTTPS URL — use for anything a browser loads. The path is the service's path: mount |
${service:frontend} |
https://myapp-acme.dev.appmecca.net |
The front door owns /, so it has no mount segment |
${service:backend:internal} |
http://backend.myapp.dev.appmecca.internal:7912 |
Private HTTP URL — use for container-to-container calls |
The exact hostname depends on your app slug, owning group and branch, so treat the examples as shape rather than as literal values.
Unknown service names are rejected before you deploy
The name in ${service:name} must match a service name in your
deploy section. A typo is caught during the repository check that runs at
mecca register and mecca build trigger, and the error lists the service
names it did find — you will not discover it at deploy time.
Complete Example¶
Here is a full appmecca.yaml for a Flask backend + Vue frontend, showing both template types:
containers:
- name: backend
dockerfile: backend/Dockerfile
context: backend/
- name: frontend
dockerfile: frontend/Dockerfile
context: frontend/
deploy:
- name: backend
container: backend
port: 5000
path: /api
health_check:
path: /api/health
- name: frontend
container: frontend
port: 80
primary: true
health_check:
path: /health
environment:
# Browser calls backend via public HTTPS
PUBLIC_API_URL: "${service:backend}"
database:
enabled: true
In the frontend container, the PUBLIC_API_URL environment variable will contain the backend's public HTTPS URL. Your frontend JavaScript can read this at runtime and use it for API calls.
When Templates Are Resolved¶
Templates are resolved at two points in the lifecycle:
-
Build time -- External (
${service:name}) templates are resolved and passed as Docker--build-argvalues. This lets you bake the URL into your frontend bundle if needed. -
Deploy time -- Both external and internal templates are resolved and injected as environment variables into the running container. Internal templates are only resolved at deploy time because the host port is not known until then.
Internal templates are skipped at build time
The ${service:name:internal} template is not available during docker build because the host port has not been allocated yet. If you need inter-service URLs at build time (e.g., for a frontend bundle), use the external template.
Using Templates in Your Code¶
Frontend (JavaScript/React/Vue/Svelte)¶
For client-side apps, the URL needs to be available in the browser. A common pattern is to read it at build time via a build argument:
Then in your JavaScript:
const API_URL = import.meta.env.VITE_API_URL;
fetch(`${API_URL}/api/items`)
.then(response => response.json())
.then(data => console.log(data));
Backend (Python/Node.js/Go)¶
For server-side code, read the environment variable at runtime:
import os
INTERNAL_AUTH_URL = os.environ.get("AUTH_SERVICE_URL")
# Makes HTTP request to the auth service via internal network
response = requests.get(f"{INTERNAL_AUTH_URL}/verify")
Common Patterns¶
Frontend calls backend (browser-side)¶
The frontend JavaScript running in the user's browser makes HTTPS requests to the backend through the public AppMecca HTTPS router.
Backend calls another backend (server-side)¶
Use the external form here too. The internal form is faster but goes stale after the callee redeploys — see the warning above.
Multiple service references¶
environment:
API_URL: "${service:backend}"
WEBSOCKET_URL: "${service:realtime}"
ASSETS_URL: "${service:media}"
You can reference as many services as you need — each name must be a service
declared in the same deploy section.
Troubleshooting¶
Template not resolving¶
If you see the literal string ${service:backend} in your container instead of a URL:
- Make sure the service name in the template matches a service
namein yourdeploysection exactly - Verify the referenced service has a
portdefined (services without ports don't get URLs) - Check that you deployed (not just built) the application
Connection refused on an internal URL¶
This is the expected symptom of the known limitation above: the target service has been redeployed since your container started, so the host port baked into the URL no longer exists.
- The fix is to switch to
${service:name}. Redeploying the calling service also works, but only until the callee is next deployed. - If you have only just deployed both, confirm the target service is running and that both are in the same environment and branch.
Next Steps¶
- Multi-Container App Example -- Full walkthrough with inter-service communication
- Domain Routing -- How URLs work in general
- Configuration: Services -- Full reference for the deploy section