Self-host workflows
A deployment is a named group of workers that owns a set of workflow definitions and receives all executions for those definitions. To self-host workflows, you run the workers yourself (on your machine for local development, or on your own infrastructure for production) and group them under a deployment name. It enables worker isolation in shared workspaces and automatic execution routing, while the platform keeps durability, scaling, and observability.
If you would rather not run workers at all, see managed deployments for workflows: Mistral Cloud builds and runs the worker for you, and the deployment concepts are the same.
Setting DEPLOYMENT_NAME
DEPLOYMENT_NAME is required at worker startup. The worker fails immediately at boot if it is not set.
DEPLOYMENT_NAME=invoice-service MISTRAL_API_KEY=your-key uv run python worker.pyValid characters: letters, digits, hyphens, underscores, and dots (max 128 characters).
WORKER_NAME identifies the individual worker process and is visible in the console and API. It defaults to socket.gethostname().
Worker isolation
In a shared workspace, multiple developers can run workers simultaneously without interfering. Each deployment only receives executions for the workflow definitions it registered.
# Developer A
DEPLOYMENT_NAME=alice MISTRAL_API_KEY=shared-key uv run python worker.py
# Developer B
DEPLOYMENT_NAME=bob MISTRAL_API_KEY=shared-key uv run python worker.pyAlice's runs land on Alice's workers. Bob's runs land on Bob's workers.
Execution routing
When only one active deployment owns a workflow, executions route automatically — no extra configuration needed:
execution = client.workflows.execute_workflow(
workflow_identifier="invoice_processor",
input={"invoice_id": "INV-001"},
)When two active deployments register the same workflow name, the platform cannot route automatically and returns 409 Conflict:
{
"code": "AMBIGUOUS_WORKFLOW",
"deployments": ["alice", "bob"]
}Resolve by passing deployment_name explicitly:
execution = client.workflows.execute_workflow(
workflow_identifier="invoice_processor",
deployment_name="alice",
input={"invoice_id": "INV-001"},
)Conflict detection
When a worker registers a workflow name already owned by a different active deployment, the platform warns immediately. Registration is not blocked — the warning is returned in the registration response and appears in worker logs:
{
"warnings": [
"Workflow 'invoice_processor' is also registered by active deployment 'bob'"
]
}The conflict resolves automatically when one of the deployments becomes inactive (its workers stop).
Multiple workers in the same deployment registering the same definitions is horizontal scaling — no warning is produced.
To restrict which users and service accounts can register workflows in a deployment, see Hardened deployments.
Deployment lifecycle
A deployment is active while at least one of its workers has heartbeated within the liveness window. Workers heartbeat every ~10 seconds automatically. When all workers stop, the deployment becomes inactive after the liveness window lapses (50 seconds in production, configurable).
Inactive deployments do not receive executions and are not counted as conflicting when checking for ambiguity.
Horizontal scaling
Run multiple workers under the same DEPLOYMENT_NAME to increase throughput. Executions are distributed across all active workers in the deployment.
For production, deploy workers as a Kubernetes Deployment or StatefulSet with replicas pointing at the same DEPLOYMENT_NAME. The platform load-balances tasks automatically.
Listing deployments
List all active deployments in your workspace:
from mistralai.client import Mistral
client = Mistral(api_key="your_api_key")
response = client.workflows.deployments.list_deployments()
for deployment in response.deployments:
print(deployment.name, deployment.is_active)Pass workflow_name to filter by workflow, or active_only=false to include inactive deployments.
Inspect a specific deployment and its individual workers:
deployment = client.workflows.deployments.get_deployment(name="invoice-service")
print(deployment.name, deployment.is_active)
for worker in deployment.workers:
print(worker.name, worker.last_heartbeat)