Scale your self-hosted deployment infrastructure
Learn how to scale your Retool deployment and infrastructure.
Retool's self-hosted Docker image consists of several containers required to run your deployment. Before you continue, you should review Retool's self-hosted architecture to understand which services need scaling as usage increases.
Scale your Retool deployment
Retool requires you to self-host production deployments on Kubernetes with Helm. For new deployments, Retool provides Terraform blueprints to provision all required infrastructure and deploy automatically. For non-production testing and development, you can use Docker.
Retool is packaged as a single stateless Docker container. The only dependency is PostgreSQL (version 13 or later) for the platform database which is used to store data such as user information, organization settings, audit logs, and applications.
To scale a Retool instance, you follow these high-level steps:
- Host the PostgreSQL database on an external system, e.g., AWS RDS. The separation of database and application allows you to independently scale and manage each service.
- Start multiple Retool containers that use the same Postgres database. The number of containers you deploy depends on your traffic and resource requirements. We recommend scaling the
apicontainer. You can do this by updating the replica count in your container orchestration service of choice. - Use a load balancer to route traffic between the Retool server containers to ensure high availability.
You should only run one replica of the jobs-runner in each Retool environment because it runs database migrations and other background tasks that should only operate as a singleton. You can scale up as many replicas as necessary of the containers/pods that run the other service types.
Configure shared Redis for replay protection
Retool prevents SAML responses from being replayed by tracking a one-time-use marker (the response's unique identifier and expiry) for each response in its cache. Without Redis, each worker process keeps its own set of markers, so the protection applies per worker rather than across your whole deployment.
Most deployments run more than one worker process: each api container runs one worker per CPU (up to three) unless you set NUM_WORKERS, and you typically run multiple containers when scaling. To enforce replay protection consistently across every worker, configure a shared Redis cache using the backend cache variables: REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_DB, and REDIS_TLS. These are separate from the REDIS_USER_CACHE_* variables, which configure caching for workflow and resource queries.
A single-worker deployment (one container with NUM_WORKERS=1) can rely on the in-memory cache and does not require Redis for replay protection.
Requires Retool self-hosted 4.0.0 or later.
Agent sandbox pool
The agent sandbox is the only Retool service that autoscales without manual configuration. The agent-sandbox-controller provisions and recycles short-lived agent-sandbox-job pods as editor sessions open and close.
How it scales
Each active editing session requires approximately one agent-sandbox-job pod. When a builder opens an app, the controller assigns a pod from the prewarm pool or provisions a new one. When the session ends, the pod is recycled.
| Component | CPU | Memory | Replicas |
|---|---|---|---|
agent-sandbox-controller | ¼ core | 256 MiB | 1 |
agent-sandbox-proxy | ¼ core | 256 MiB | 1 |
agent-sandbox-job pods | 1 core | 2 GiB | ~1 per active editor |
r2-worker | 1 core | 2 GiB | 1 |
js-executor | 2 cores | 6 GiB | 1 (up to 10 with autoscaling enabled) |
The controller, proxy, and r2-worker do not need to be replicated. r2-worker and js-executor are separate rr.* components (not part of the sandbox pool itself), but both are enabled by the same rr.enabled master switch and their default resource requests are fixed regardless of sandbox activity — factor them into capacity planning alongside the sandbox components.
The Git server (rr.gitServer) runs in-process on the main backend pod by default and adds no separate fixed workload. It only becomes its own deployment, with its own resource footprint, if you explicitly set rr.gitServer.separate.enabled: true — and even then it falls back to the same resource defaults as the main backend rather than a sandbox-specific fixed cost.