Skip to content

Self-hosting

Architecture

Services, dependencies, request paths, and durable state in a self-hosted deployment

Sim runs an app, a realtime server, PostgreSQL, Redis, and a scheduler. This page shows their dependencies and the state you need to preserve.

Services

ServiceImagePortStateRequired
appghcr.io/simstudioai/simstudio3000Local uploads unless shared storage is configuredYes
realtimeghcr.io/simstudioai/realtime3002In-flight collaboration stateYes
migrationsghcr.io/simstudioai/migrations—One-shot schema and data migrationsYes
postgresqlpgvector/pgvector:pg175432Durable application dataYes
redisredis:7-alpine6379Cache, coordination, and live eventsBundled by default; required across replicas
cronghcr.io/simstudioai/cron (Compose) / curlimages/curl (Kubernetes)—NoneRequired for scheduled work
piighcr.io/simstudioai/pii5001NoneOptional
ollamaollama/ollama11434Model cacheOptional
telemetryotel/opentelemetry-collector-contrib4317/4318NoneOptional

App

The Next.js app serves the workflow builder, API routes, and workflow orchestration. Local JavaScript runs in Node child workers using isolated-vm inside the app container. The app and those workers share the container's memory budget. The Helm chart requests 4 GiB and limits the app to 8 GiB; docker-compose.prod.yml sets an 8 GB memory limit without a reservation.

E2B or Daytona moves supported code execution to a remote sandbox. TRIGGER_DEV_ENABLED routes asynchronous jobs to Trigger.dev; the default deployment uses database-backed jobs. See Sandboxes for the provider and image requirements.

Any replica can serve files once shared object storage is configured. Before adding replicas, configure storage, Redis, and database connection capacity as described in Scaling and high availability.

Realtime

The Bun Socket.IO server carries collaborative editing, live execution updates, and collaborative documents. Clients connect at /socket.io.

Realtime shares PostgreSQL and BETTER_AUTH_SECRET with the app, using Better Auth's shared-database-session pattern. It authenticates the same accounts without a separate login.

A realtime server must exist for editing and live updates. Set realtime.enabled: false in Helm only when app.env.SOCKET_SERVER_URL points to a realtime instance you run separately.

Migrations

The migrator applies Drizzle SQL and registered data migrations, then exits. Compose runs it as a one-shot service. Helm runs it as an app init container, so migrations complete before that app pod starts. Later pods and rollouts run the migrator again; already-applied migrations are skipped.

Migrations are forward-only. See Upgrades for backup and rollback procedures.

PostgreSQL

Sim requires PostgreSQL with the pgvector extension for knowledge base embeddings. The bundled image uses PostgreSQL 17 and includes pgvector. On managed PostgreSQL, make the extension available; migrations issue CREATE EXTENSION where permissions allow.

PostgreSQL holds workflows, runs, logs, accounts, organizations, credentials, knowledge base chunks and embeddings, table data, and upload-session state.

Redis

Redis carries live events and stores shared coordination state. Some stores fall back to PostgreSQL or process-local state, but cross-pod collaboration has no local fallback. CLI API-key pairing also requires Redis, even with one replica; OAuth login uses a separate path. See Redis for the full fallback matrix.

Scheduler

Scheduled workflows, polling triggers, connector syncs, subscription renewal, and maintenance jobs call authenticated app endpoints. Helm provides CronJobs; Compose provides a supercronic service. See Background jobs for the shipped inventory and the additional upload-session cleanup schedule operators must configure.

Optional Chat service

The chart can also render the optional copilot service, its separate PostgreSQL database, and its migration job. These are separate from the app and workflow database. Enabling them requires the service's image, license, credentials, and database configuration; see the chart's copilot values and reference architectures.

Where state lives

StoreContentsBackup
PostgreSQLApplication data, including any separately enabled Chat-service databasepg_dump, managed snapshots, and point-in-time recovery
Object storageFiles, knowledge base documents, execution outputs, avatars, and logosBucket versioning and lifecycle policies
SecretsENCRYPTION_KEY, API_ENCRYPTION_KEY, BETTER_AUTH_SECRET, INTERNAL_API_SECRET, CRON_SECRETSecret manager and separate recovery copies

Redis is a cache and message bus, not the owner of committed application data. Losing it interrupts in-flight coordination and live updates; completed data remains in PostgreSQL and object storage.

Request paths

TrafficPath
Editor / APIBrowser → ingress or reverse proxy → app:3000 → PostgreSQL, Redis, storage
CollaborationBrowser → ingress → realtime:3002 (/socket.io, WebSocket upgrade) → Redis → other realtime pods
Cloud uploadBrowser → app opens upload session → signed transfer instructions → browser uploads directly to storage → app verifies completion and records metadata
Local uploadBrowser → app opens upload session → bytes stream through /api/v2/uploads/... to local disk
Workflow executionManual, API, webhook, or schedule trigger → app enqueues or orchestrates run → local code workers or remote sandbox → results/logs to PostgreSQL, progress markers to Redis
Background workScheduler → Authorization: Bearer $CRON_SECRET → internal app endpoint

Cloud uploads use a single PUT through 50 MiB and multipart above that. Local uploads use a single PUT through 8 MiB and multipart above that. Cloud buckets need CORS for the Sim origin and must be reachable from browsers; downloads are proxied through the app. Local uploads need no bucket CORS configuration.

Network boundaries

FromToPurpose
Internetapp:3000, realtime:3002Browser/API traffic
App, realtimePostgreSQL:5432, Redis:6379Data and coordination
AppObject-storage endpointStorage operations and proxied downloads
BrowserObject-storage endpointSigned uploads
AppModel/integration APIs and email providerOutbound calls
SchedulerInternal app:3000Scheduled work

The proxy must support WebSocket upgrades, streams, and long-lived connections. The chart's optional NetworkPolicy excludes cloud metadata addresses from broad egress, but its default ingress peer is broad. Configure the actual peers and managed-datastore paths before enabling it.

Was this helpful?
Suggest an edit