# Appsmith Admin Guide

This guide is for the people who **run, secure, scale, and extend** Appsmith: platform administrators, DevOps/SRE engineers, security reviewers, and developers who want to understand the codebase. It covers Appsmith's architecture, the complete configuration reference, deployment topologies, security hardening, day-2 operations, and internals down to the plugin SPI and reactive request pipeline.

For app-building (widgets, queries, bindings, publishing), see the companion **Appsmith User Guide** — this document links to it where the two overlap.

> **Scope and edition note.** Appsmith builds two editions from one repository: **Community Edition (CE)**, Apache-2.0 licensed (`appsmith/appsmith-ce`), and **Enterprise Edition (EE)** (`appsmith/appsmith-ee`), which layers SAML/enterprise SSO, granular RBAC, audit logs, and business features behind a license key. The codebase expresses this as a `ce/` (community) vs. `ee/` (enterprise) split throughout both client and server. This guide centers on CE and flags EE-only surfaces.

---

## Table of Contents

1. [Executive Summary](#1-executive-summary)
2. [Architecture](#2-architecture)
3. [Requirements](#3-requirements)
4. [Configuration Mastery](#4-configuration-mastery)
5. [Deployment](#5-deployment)
6. [Security](#6-security)
7. [Operations](#7-operations)
8. [Troubleshooting](#8-troubleshooting)
9. [Developer Internals](#9-developer-internals)
10. [Code Quality and Conventions](#10-code-quality-and-conventions)
11. [Potential Improvements](#11-potential-improvements)
12. [Contributing](#12-contributing)
13. [Quick Reference](#13-quick-reference)

---

## 1. Executive Summary

Appsmith is a self-hosted, open-source **low-code platform** for building internal applications. Administrators deploy a single artifact — the Appsmith container — and end users build and run web apps inside it against their own databases and APIs.

**What you operate:**

| Aspect | Summary |
| --- | --- |
| **Distribution** | A single "fat" Docker image bundling the web editor, application server, real-time service, and databases, supervised by `supervisord`. Also packaged as a Helm chart, AWS AMI, and platform-specific manifests. |
| **Backend** | Java 25, Spring Boot **WebFlux** (fully reactive, non-blocking on Netty), Spring Security, with a Maven multi-module layout and a plugin SPI for datasource connectors. |
| **Frontend** | React 17 + Redux + Redux-Saga, TypeScript, built with Yarn workspaces; a sandboxed evaluation worker drives reactive bindings. |
| **Real-Time Service (RTS)** | A Node.js/TypeScript service for AST parsing, evaluation helpers, and Git operations. |
| **Persistence** | Application metadata and encrypted credentials in a bundled database (MongoDB, migrating to PostgreSQL), Redis for caching/sessions, and a Git working tree on disk. All under one persistent volume: `/appsmith-stacks`. |
| **Edge** | Caddy v2 inside the container terminates HTTP(S), auto-provisions TLS, and routes to the internal services. |

**Key operational facts to internalize early:**

- **One volume holds everything.** `/appsmith-stacks` contains configuration (`docker.env`), the embedded databases' data, Git working copies, and logs. Back it up; protect it; never let two containers share it.
- **Two secrets are load-bearing.** `APPSMITH_ENCRYPTION_PASSWORD` and `APPSMITH_ENCRYPTION_SALT` encrypt stored datasource credentials. Lose or change them and every saved credential becomes undecryptable.
- **The server is reactive.** No thread-per-request; concurrency comes from the event loop. Memory (JVM heap) is the lever that matters most for a single container.
- **Migrations run on boot.** The server applies schema migrations automatically at startup — always back up before upgrading the image.

---

## 2. Architecture

### 2.1 The single-container ("fat container") model

The default Appsmith deployment is **one container running many processes**, orchestrated by `supervisord`. This trades the operational simplicity of "one thing to run" for a denser footprint.

```text
                        Internet / LAN
                              │
                        host:8080 → container:80
                              │
        ┌─────────────────────────────────────────────────────┐
        │  Appsmith container (appsmith/appsmith-ce | -ee)      │
        │                                                       │
        │   supervisord  (PID 1 process manager)                │
        │     ├── editor   → Caddy v2  :80   (TLS, routing)     │
        │     │      ├── /api/*  → backend :8080                │
        │     │      ├── /rts/*  → rts     :8091                │
        │     │      └── /*      → React build (static)         │
        │     ├── backend  → Java Spring WebFlux  :8080         │
        │     ├── rts      → Node.js RTS          :8091         │
        │     ├── postgres → embedded PostgreSQL  :5432         │
        │     ├── mongodb  → embedded MongoDB     :27017        │
        │     └── redis    → embedded Redis       :6379         │
        │                                                       │
        │   Persistent volume: /appsmith-stacks                 │
        │     ├── configuration/docker.env                      │
        │     ├── data/ (mongo, postgres)                       │
        │     ├── git-storage/  (per-app Git working copies)    │
        │     └── logs/                                         │
        └─────────────────────────────────────────────────────┘
```

The six supervised programs are literally named `editor`, `backend`, `rts`, `postgres`, `mongodb`, and `redis` (see `deploy/docker/fs/opt/appsmith/templates/supervisord/`). The container's `healthcheck.sh` verifies each is `RUNNING` and additionally curls the editor (`http://localhost/`) and the server health endpoint (`http://localhost:8080/api/v1/health`).

> [!NOTE]
> Bundled databases are a convenience for single-node installs. For production and Kubernetes, you typically **disable the embedded databases** and point Appsmith at external, managed MongoDB/PostgreSQL/Redis via the connection-string environment variables (§4). This is what makes horizontal scaling and proper backups feasible.

### 2.2 Boot sequence

```text
ENTRYPOINT
  └── deploy/docker/fs/opt/appsmith/entrypoint.sh
        ├── set up nss_wrapper (run as arbitrary non-root UID)
        ├── configure HTTP(S)_PROXY / NO_PROXY
        ├── init_env_file:  render /appsmith-stacks/configuration/docker.env
        │      from current APPSMITH_* env + templates/docker.env.sh
        ├── caddy-reconfigure.mjs: generate Caddy config from env (domain, TLS)
        └── start_app.sh → supervisord (reads /etc/supervisor/supervisord.conf,
               includes per-process *.conf from templates/supervisord/)
```

The env file is **rendered once at boot** by merging the process environment (any `APPSMITH_*`/`MONGO_*` variables you pass to the container) with `templates/docker.env.sh` defaults, and persisted to `/appsmith-stacks/configuration/docker.env`. On subsequent restarts, that file is the source of truth — which is why you edit it (or pass new env vars) and restart to change configuration.

### 2.3 Backend: reactive Spring on a multi-module Maven build

The server (`app/server`) is a Maven reactor with these modules:

| Module | Responsibility |
| --- | --- |
| `appsmith-server` | The Spring Boot WebFlux application: controllers, services, security, domains, migrations. |
| `appsmith-interfaces` | Shared interfaces/contracts between server and plugins. |
| `appsmith-plugins` | The 25 datasource connector modules (one per plugin). |
| `appsmith-git` | Git operations library (JGit-based) used for app version control. |
| `reactive-caching` | A reactive caching abstraction (Redis-backed). |

The application uses `spring-boot-starter-webflux` (not Spring MVC), `spring-boot-starter-security` (reactive security filter chain), `spring-boot-starter-data-mongodb-reactive` and `spring-boot-starter-data-redis-reactive`, `spring-boot-starter-aop` (cross-cutting telemetry/feature aspects under `server/aspect`), and `spring-boot-starter-mail`. Java version is **25** (`<java.version>25</java.version>`).

Because it is reactive, every controller method returns a Reactor publisher — `Mono<T>` for single results, `Flux<T>` for streams — and runs non-blocking on Netty. `server.shutdown=graceful` with a 20-second drain phase means in-flight requests complete before the JVM exits (important for rolling updates).

### 2.4 The REST API surface

All endpoints are versioned under `/api/v1`. The controller layer (`server/controllers`) maps to these resource roots:

| Resource root | Controller | Domain |
| --- | --- | --- |
| `/api/v1/health` | `HealthCheckController` | Liveness/readiness probe. |
| `/api/v1/login`, `/logout` | (security) | Authentication. |
| `/api/v1/users` | `UserController` | Users, invites, profile. |
| `/api/v1/workspaces` | `WorkspaceController` | Workspaces (teams). |
| `/api/v1/tenants` | `OrganizationController` | Instance/organization settings. |
| `/api/v1/applications` | `ApplicationController` | Applications. |
| `/api/v1/pages` | `PageController` | Pages within an app. |
| `/api/v1/layouts` | `LayoutController` | Page layout / DSL. |
| `/api/v1/actions` | `ActionController` | Queries/actions. |
| `/api/v1/collections/actions` | `ActionCollectionController` | JS Objects. |
| `/api/v1/datasources` | `DatasourceController` | Saved datasource connections. |
| `/api/v1/plugins` | `PluginController` | Available connector plugins. |
| `/api/v1/git`, `/git/applications`, `/git/artifacts` | `GitController` | App version control. |
| `/api/v1/themes` | `ThemeController` | App theming. |
| `/api/v1/import`, `/saas` | `RestApiImportController`, `SaasController` | Import (e.g. cURL) / SaaS auth. |
| `/api/v1/libraries` | `CustomJSLibController` | Custom JS libraries. |
| `/api/v1/consolidated-api` | `ConsolidatedAPIController` | A single call that returns all data needed to bootstrap an app view (page-load optimization). |
| `/api/v1/admin` | `InstanceAdminController` | Instance admin settings. |
| `/api/v1/product-alert` | `ProductFeatureAlertController` | Product alerts/banners. |
| `/api/v1/search-entities` | `SearchEntityController` | Global entity search. |
| `/api/v1/app-templates` | `ApplicationTemplateController` | Template gallery. |
| `/api/v1/usage-pulse` | `UsagePulseController` | Usage heartbeat. |
| `/api/v1/assets` | `AssetController` | Uploaded assets/files. |

> [!TIP]
> The `consolidated-api` endpoint is a deliberate performance optimization: instead of the client firing a dozen requests to render an app, it batches the bootstrap data into one round trip. If you see a single large request on app load, that's it.

### 2.5 Frontend: reactive evaluation in the browser

The client (`app/client`) is a React 17 SPA using **Redux** for state and **Redux-Saga** for all asynchronous side effects (API calls, evaluation orchestration, Git operations). Sagas follow the watcher/worker pattern — a `rootSaga` forks watcher sagas that `takeLatest`/`takeEvery` on dispatched actions and spawn worker sagas which `call` the API client classes (`src/api/*Api`, `src/ce/api/*Api`, each extending a base `Api`/`API` class) and `put` success/error actions.

The platform's defining client feature is the **evaluation engine**: a sandboxed web worker (`src/workers/Evaluation`) that maintains a **dependency map** (`workers/common/DependencyMap`) of every binding, widget property, query, and JS variable. When any value changes, it recomputes exactly the dependent nodes and re-renders — this is the reactivity users experience. A linting plugin (`plugins/Linting`) and a Tern-based language service (`workers/Tern`) provide inline error-checking and field-aware autocomplete in the code editors (CodeMirror 5).

Three layout systems coexist: **fixedlayout** (pixel grid), **autolayout** (responsive reflow), and **anvil** (the newer Section/Zone responsive system paired with the **WDS** widget family). A parallel `ce/` vs `ee/` source tree implements the community/enterprise split.

### 2.6 The Real-Time Service (RTS)

`app/client/packages/rts` is a separate Node.js/TypeScript service (default port **8091**, `APPSMITH_RTS_PORT`). It runs the server-side AST work (`packages/ast`), evaluation helpers, and Git plumbing that benefits from a JS runtime, and exposes internal routes (e.g. a git `POST /reset`). Caddy proxies `/rts/*` to it. It is started by supervisord (`run-rts.sh` → `node bundle/server.js`) and is not a public, user-facing API.

### 2.7 Datasource plugin architecture

Each connector under `app/server/appsmith-plugins/` is an independent Maven module implementing the plugin SPI defined in `appsmith-interfaces`. A plugin provides a `PluginExecutor` that knows how to (a) build/test a datasource connection, (b) execute an action against it, and (c) describe its form/template. The server discovers and loads plugins, so adding a connector is additive and isolated.

The 25 bundled plugins: `postgresPlugin`, `mysqlPlugin`, `mssqlPlugin`, `oraclePlugin`, `snowflakePlugin`, `redshiftPlugin`, `databricksPlugin`, `mongoPlugin`, `arangoDBPlugin`, `dynamoPlugin`, `firestorePlugin`, `elasticSearchPlugin`, `redisPlugin`, `restApiPlugin`, `graphqlPlugin`, `amazons3Plugin`, `awsLambdaPlugin`, `googleSheetsPlugin`, `smtpPlugin`, `openAiPlugin`, `anthropicPlugin`, `googleAiPlugin`, `appsmithAiPlugin`, `saasPlugin`, `jsPlugin`.

> [!NOTE]
> This is the same "core + provider-plugin ecosystem" shape as other integration platforms: the platform defines the contract once, and each connector is a thin, swappable implementation. Operationally, this means a single misbehaving connector is isolated to its plugin module.

---

## 3. Requirements

### 3.1 Host sizing

| Profile | CPU | Memory | Disk | Notes |
| --- | --- | --- | --- | --- |
| Evaluation (single container, bundled DBs) | 1–2 vCPU | 2–4 GB | 10 GB | Fine for trials and small teams. |
| Small production (single container) | 2–4 vCPU | 4–8 GB | 20+ GB | Bundled or external DBs; tune JVM heap. |
| Production HA (Kubernetes) | per-pod requests `500m` CPU / `3000Mi` memory (chart default) | Scale pods | External DBs + RWX PVC | Use external MongoDB/PostgreSQL/Redis. |

### 3.2 Network and ports

| Port (container) | Service | Exposure |
| --- | --- | --- |
| `80` | Caddy (edit/view, API, RTS) | The only port you publish. |
| `443` | Caddy TLS (when a custom domain is set) | Publish for HTTPS. |
| `8080` | Java server | Internal only. |
| `8091` | RTS | Internal only. |
| `27017` / `5432` / `6379` | Mongo / Postgres / Redis | Internal only (or external endpoints). |

Outbound: Appsmith must reach the datasources users connect to, your SMTP server (if email is enabled), and — unless telemetry is disabled — Appsmith's cloud services for template fetching and anonymized usage pulses.

### 3.3 Persistent storage

A durable volume mounted at `/appsmith-stacks` is **required**. On Kubernetes use a `ReadWriteMany`-capable `StorageClass` (the chart defaults to `accessModes: [ReadWriteMany]`, `size: 10Gi`, `reclaimPolicy: Retain`). EFS is supported via the chart's `persistence.efs` options.

---

## 4. Configuration Mastery

Appsmith is configured almost entirely through `APPSMITH_*` environment variables. At boot these are rendered into `/appsmith-stacks/configuration/docker.env`; on Kubernetes they come from the `applicationConfig` map (or a referenced `secretName`) in the Helm values. Spring maps them onto `application-ce.properties` keys.

> [!CAUTION]
> Do **not** confuse runtime config with **build-time** client variables. Names like `NODE_ENV`, `PUBLIC_URL`, `WDS_SOCKET_*`, `REACT_APP_*`, `BUILD_PATH`, and `INLINE_RUNTIME_CHUNK` (seen in `app/client/config/`) configure the React **build** and webpack dev server — they are for *developing the client*, not for operating a deployed instance. Runtime configuration is the `APPSMITH_*` set below.

### 4.1 Required / core

| Variable | Default | Purpose |
| --- | --- | --- |
| `APPSMITH_ENCRYPTION_PASSWORD` | — | **Required.** Secret used to encrypt stored datasource credentials. Set once to a long random string. |
| `APPSMITH_ENCRYPTION_SALT` | — | **Required.** Salt paired with the encryption password. |
| `APPSMITH_CUSTOM_DOMAIN` | empty | Public domain. When set, Caddy auto-provisions Let's Encrypt TLS. |
| `APPSMITH_DISABLE_TELEMETRY` | `false`* | Disable anonymized usage telemetry. (*The env template ships `false`; `application-ce.properties` defaults the Spring side to `true` when unset.) |

### 4.2 Databases and cache

| Variable | Purpose |
| --- | --- |
| `APPSMITH_DB_URL` | Primary metadata DB connection (MongoDB URI form, e.g. `mongodb://user:pass@host:27017/appsmith`). |
| `APPSMITH_MONGODB_URI` | Alternative Mongo URI; if set, it is promoted to `APPSMITH_DB_URL` at boot. |
| `APPSMITH_MONGODB_USER` / `APPSMITH_MONGODB_PASSWORD` | Embedded-Mongo credentials. |
| `APPSMITH_POSTGRES_DB_URL` | PostgreSQL connection (the platform is migrating its metadata store to Postgres). |
| `APPSMITH_PG_DATABASE` | Postgres database name (default `appsmith`). |
| `APPSMITH_REDIS_URL` | Redis connection (`redis://:password@host:6379`). Sessions and cache. |
| `APPSMITH_REDIS_PASSWORD` | Redis password. |
| `APPSMITH_REDIS_GIT_URL` | Redis URL used for Git-related coordination. |
| `APPSMITH_ENABLE_EMBEDDED_DB` | Toggle the in-container database. Set to disable when using external DBs. |

> [!TIP]
> For production, set the three connection URLs to **external** managed services and disable the embedded databases. This decouples your data lifecycle (backups, HA, scaling) from the Appsmith container and is a prerequisite for running more than one replica.

### 4.3 Authentication and SSO

| Variable | Purpose |
| --- | --- |
| `APPSMITH_ADMIN_EMAILS` | Comma-separated emails granted instance super-admin. |
| `APPSMITH_FORM_LOGIN_DISABLED` | Disable email/password login (force SSO). |
| `APPSMITH_SIGNUP_DISABLED` | Disable open self-signup. |
| `APPSMITH_SIGNUP_ALLOWED_DOMAINS` | Restrict signup to listed email domains. |
| `APPSMITH_OAUTH2_GOOGLE_CLIENT_ID` / `_SECRET` / `_REDIRECT_URI` | Google OAuth SSO. |
| `APPSMITH_OAUTH2_GITHUB_CLIENT_ID` / `_SECRET` | GitHub OAuth SSO. |
| `APPSMITH_OAUTH2_OIDC_CLIENT_ID` / `_SECRET` | Generic OIDC SSO. |
| `APPSMITH_OAUTH2_ALLOWED_DOMAINS` | (Deprecated, see `SIGNUP_ALLOWED_DOMAINS`) restrict OAuth logins by domain. |
| `APPSMITH_DISABLE_EMBEDDED_KEYCLOAK` | Turn off the bundled Keycloak (used for SAML/enterprise SSO). |
| `APPSMITH_KEYCLOAK_DB_URL` / `_USERNAME` / `_PASSWORD` / `_DRIVER` | External database for Keycloak. |
| `APPSMITH_LICENSE_KEY` | Enterprise license key (EE). |

### 4.4 Email (SMTP)

| Variable | Purpose |
| --- | --- |
| `APPSMITH_MAIL_ENABLED` | Master switch for outbound email (invites, password resets). |
| `APPSMITH_MAIL_HOST` / `APPSMITH_MAIL_PORT` | SMTP server. |
| `APPSMITH_MAIL_USERNAME` / `APPSMITH_MAIL_PASSWORD` | SMTP auth. |
| `APPSMITH_MAIL_FROM` / `APPSMITH_REPLY_TO` | From/Reply-To addresses. |
| `APPSMITH_MAIL_SMTP_AUTH` | `true`/`false` — enable SMTP AUTH. |
| `APPSMITH_MAIL_SMTP_TLS_ENABLED` | `true`/`false` — STARTTLS. |

### 4.5 Security and limits

| Variable | Default | Purpose |
| --- | --- | --- |
| `APPSMITH_ALLOWED_FRAME_ANCESTORS` | `'self' *` (template) | CSP `frame-ancestors` — which domains may embed Appsmith in an iframe. Set to a specific allowlist (or `'none'`) to control embedding. |
| `APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX` | `false` | Whether the Iframe widget runs without the browser sandbox. Keep `false`. |
| `APPSMITH_RATE_LIMIT` | — | Request rate limiting. |
| `APPSMITH_RECAPTCHA_SITE_KEY` / `_SECRET_KEY` / `_ENABLED` | — | Google reCAPTCHA for login/signup hardening. |
| `APPSMITH_CODEC_SIZE` | `150` (MB) | Max in-memory request/response size for the reactive codec (`spring.codec.max-in-memory-size`). Raise for very large payloads/imports. |
| `APPSMITH_PLUGIN_MAX_RESPONSE_SIZE_MB` | `5` | Cap on a single query response size. |

> [!WARNING]
> `APPSMITH_ALLOWED_FRAME_ANCESTORS` defaults in the env template to `'self' *`, which permits embedding from **any** origin. If you do not intend to embed Appsmith apps elsewhere, tighten this to `'self'` or a specific domain allowlist to prevent clickjacking.

### 4.6 JVM, logging, telemetry, and domain

| Variable | Purpose |
| --- | --- |
| `APPSMITH_JAVA_ARGS` | Extra JVM flags, e.g. `-Xms1g -Xmx2g`. The primary lever for server memory. |
| `APPSMITH_JAVA_HEAP_ARG` | Heap sizing argument. |
| `APPSMITH_GIT_ROOT` | Git working-copy root. Default `/appsmith-stacks/git-storage`. |
| `APPSMITH_LOG_DIR` | Log directory (under the stacks volume). |
| `APPSMITH_CLIENT_LOG_LEVEL` | Browser console log level (`debug`/`error`). |
| `APPSMITH_VERBOSE_LOGGING_ENABLED` | Verbose server logging. |
| `APPSMITH_SENTRY_DSN` / `_ENVIRONMENT`, `APPSMITH_SERVER_SENTRY_DSN` / `_ENVIRONMENT` | Sentry error reporting (client/server). |
| `APPSMITH_SEGMENT_KEY` / `APPSMITH_SEGMENT_CE_KEY` | Product analytics keys. |
| `APPSMITH_DISABLE_MONITORING` / `APPSMITH_MONITORING` / `APPSMITH_NEW_RELIC_ACCOUNT_ENABLE` | APM/monitoring toggles. |
| `APPSMITH_CLOUD_SERVICES_BASE_URL` | Base URL for Appsmith cloud services (templates, signatures). |
| `APPSMITH_CUSTOM_DOMAIN` | Public domain → triggers Caddy TLS. |
| `APPSMITH_VERSION_ID` / `APPSMITH_VERSION_SHA` / `APPSMITH_VERSION_RELEASE_DATE` | Build/version stamps (set by the image). |

> [!TIP]
> The full, authoritative list of recognized keys is the platform's environment-variable documentation; the Helm chart's `applicationConfig` schema explicitly notes its enumerated keys are "common starting points and are not exhaustive." Treat the tables above as the operationally important subset.

---

## 5. Deployment

### 5.1 Docker / Docker Compose (recommended for single-node)

The repository's reference compose file (`deploy/docker/docker-compose.yml`) is intentionally minimal:

```yaml
services:
  appsmith:
    image: index.docker.io/appsmith/appsmith-ce:release
    container_name: appsmith
    ports:
      - "8080:80"
    environment:
      APPSMITH_ENCRYPTION_PASSWORD: <long-random-secret>
      APPSMITH_ENCRYPTION_SALT: <long-random-secret>
    volumes:
      - ./stacks:/appsmith-stacks
```

Operational tasks:

```bash
docker compose up -d            # start / apply config changes
docker compose pull && docker compose up -d   # upgrade
docker logs -f appsmith         # tail logs
docker exec -it appsmith bash   # shell into the container
```

To enable HTTPS, set `APPSMITH_CUSTOM_DOMAIN` to your domain, publish port 443, and point DNS at the host — Caddy obtains and renews the certificate automatically.

### 5.2 Kubernetes via Helm (recommended for production/HA)

The chart lives in `deploy/helm`. Key characteristics from `values.yaml`:

- **Workload:** `StatefulSet` by default (`workload.kind`); switches to `Deployment` when autoscaling is enabled. Default `image.repository: appsmith/appsmith-ee`, tag `latest`.
- **Persistence:** PVC with `ReadWriteMany`, `10Gi`, `Retain` reclaim policy; EFS and existing-claim options provided.
- **Bundled dependencies (subcharts):** Bitnami **redis**, **mongodb** (replicaset), and **postgresql** (the Postgres subchart primarily backs Keycloak). Each can be disabled to use external services.
- **MongoDB topology options:** classic Bitnami replicaset, or the newer **MongoDBCommunity** operator path (`mongodbCommunity` + `mongodbOperator`, a 3.7.0 preview for fresh installs).
- **Exposure:** `Service` (default `ClusterIP`, port 80) and optional `Ingress` (class `nginx`, TLS via cert-manager/self-signed/custom secrets).
- **Scaling:** HPA (`autoscaling`) or **KEDA** (`keda`), mutually exclusive; `PodDisruptionBudget` enabled with `minAvailable: 1`.
- **Resources:** default requests `cpu: 500m`, `memory: 3000Mi`.
- **Config:** `applicationConfig` map of `APPSMITH_*` vars, or reference an existing secret via `secretName`. Custom CA certs via `customCAcert`.

```bash
helm install appsmith ./deploy/helm \
  --namespace appsmith --create-namespace \
  --set applicationConfig.APPSMITH_ENCRYPTION_PASSWORD=<secret> \
  --set applicationConfig.APPSMITH_ENCRYPTION_SALT=<secret> \
  --set applicationConfig.APPSMITH_CUSTOM_DOMAIN=appsmith.example.com
```

> [!IMPORTANT]
> For any multi-replica deployment you **must** externalize state: point `APPSMITH_DB_URL`/`APPSMITH_POSTGRES_DB_URL`/`APPSMITH_REDIS_URL` at shared, managed databases, and use a `ReadWriteMany` volume for `/appsmith-stacks`. Two replicas sharing a non-RWX volume or each running their own embedded DB will corrupt or diverge state.

### 5.3 Other targets

`deploy/` also ships AWS AMI/Packer images, an Ansible playbook (`deploy/ansible`), DigitalOcean and Heroku manifests, and AWS CloudFormation/AMI assets. These wrap the same container and configuration model.

---

## 6. Security

### 6.1 Secrets and credential encryption

- Datasource credentials are stored **encrypted** using `APPSMITH_ENCRYPTION_PASSWORD` + `APPSMITH_ENCRYPTION_SALT`. Manage these like database root passwords: long, random, stored in a secret manager, never rotated casually (rotation invalidates all stored credentials).
- On Kubernetes, supply secrets via `secretName` (an existing `Secret`) rather than inline `applicationConfig`, and consider the chart's **External Secrets Operator** integration (`externalSecrets.enabled`).

### 6.2 Authentication hardening

- Disable open signup in shared/production instances: `APPSMITH_SIGNUP_DISABLED=true`, or restrict with `APPSMITH_SIGNUP_ALLOWED_DOMAINS`.
- Force SSO by disabling form login (`APPSMITH_FORM_LOGIN_DISABLED=true`) once OAuth/OIDC/SAML is configured.
- Enable reCAPTCHA (`APPSMITH_RECAPTCHA_*`) to harden the login/signup surface against automated abuse.
- Reactive Spring Security (`server/authentication/handlers`) drives the OAuth2 login flows for Google/GitHub/OIDC; EE adds SAML via embedded Keycloak.

### 6.3 Network and embedding

- Terminate TLS at Caddy (custom domain) or at an upstream LB/Ingress; never expose the internal `:8080`/`:8091` ports.
- Lock down `APPSMITH_ALLOWED_FRAME_ANCESTORS` to prevent clickjacking unless you intentionally embed apps.
- Keep `APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX=false` so user-authored Iframe widgets remain sandboxed.

### 6.4 Query safety

- Bound values in SQL queries are sent as **prepared-statement parameters** by default — keep this on. Treat any datasource that disables prepared statements as a SQL-injection review item.
- Use **least-privilege** datasource accounts (read-only for dashboards). Appsmith executes queries with whatever rights the configured account has.

### 6.5 Runtime posture

- The container supports running as an **arbitrary non-root UID** via `nss_wrapper` (set `securityContext.runAsNonRoot`/`runAsUser` on K8s). The image build also strips setuid/setgid bits.
- Restrict egress to only the datasources, SMTP, and (if telemetry stays on) Appsmith cloud services your instance needs.

> [!CAUTION]
> Because end users can write JavaScript and connect arbitrary datasources, treat an Appsmith instance as a powerful tool: scope who can create datasources, segment workspaces by trust boundary, and put the instance behind your SSO and network controls.

---

## 7. Operations

### 7.1 Health and liveness

| Check | How |
| --- | --- |
| Process health | `docker exec appsmith /opt/appsmith/healthcheck.sh` — verifies each supervised process is `RUNNING` and curls editor + server. |
| Server health endpoint | `curl http://localhost:8080/api/v1/health` (internal) or `https://<domain>/api/v1/health`. |
| Supervisor status | `docker exec appsmith supervisorctl status`. |

### 7.2 Logs

Logs land under `/appsmith-stacks/logs/` (and `APPSMITH_LOG_DIR`). Supervisor multiplexes each process's stdout/stderr to the container's main stream via a custom event listener, so `docker logs appsmith` shows interleaved, per-process-labeled output.

> [!NOTE]
> A known community item ([#41876](https://github.com/appsmithorg/appsmith/issues/41876)) notes that on Kubernetes the supervisord stdout prefix can interfere with Caddy access-log parsing. Track it if you build log pipelines that parse Caddy output.

### 7.3 Backup and restore

Appsmith ships an in-container control utility (`appsmithctl`, implemented in `app/client/packages/rts/src/ctl`) with `backup`, `restore`, `export_db`, and `import_db` subcommands.

```bash
# Create a backup archive (written under the stacks volume)
docker exec appsmith appsmithctl backup

# Restore from a backup archive
docker exec appsmith appsmithctl restore
```

A backup captures the metadata database and configuration. For a belt-and-suspenders approach, also snapshot the entire `/appsmith-stacks` volume (which additionally includes Git working copies under `git-storage/`).

> [!IMPORTANT]
> Run a backup **before every upgrade**. The server applies schema migrations on startup; a pre-upgrade backup is your rollback path.

### 7.4 Database migration tooling (MongoDB → PostgreSQL)

The image includes helpers for the metadata-store migration and Postgres maintenance: `pg-upgrade.sh`, `pg-utils.sh`, `run-postgres.sh`, `appsmith_hba.conf`, the supervisord `postgres.conf`/`mongodb.conf`, and `mongodb-fixer.sh`. If you are moving an existing MongoDB-backed instance forward, follow the official migration runbook and back up first — both data paths exist in the codebase during the transition.

### 7.5 Diagnostics and performance capture

For incident response the container bundles JVM diagnostics scripts:

| Script | Purpose |
| --- | --- |
| `diagnostics.sh` | Collect a diagnostics bundle. |
| `memory-analysis.sh`, `record-heap-dump.sh` | Heap usage / heap dump. |
| `record-thread-dump.sh`, `thread-profile-start.sh` / `thread-profile-stop.sh` | Thread dumps / profiling. |
| `JFR-recording-24-hours.sh` | 24-hour Java Flight Recorder capture. |
| `auto_heal.sh` | Auto-recovery hook (`APPSMITH_AUTO_HEAL`). |
| `generate-infra-details.sh` | Gather host/infra details for support. |

### 7.6 Upgrades

```bash
docker exec appsmith appsmithctl backup     # 1. back up
docker compose pull                          # 2. fetch new image
docker compose up -d                         # 3. recreate (migrations run on boot)
docker exec appsmith /opt/appsmith/healthcheck.sh   # 4. verify
```

On Kubernetes the `StatefulSet`/`Deployment` rolling update plus graceful shutdown drains in-flight requests; gate rollout on the readiness/health probe.

---

## 8. Troubleshooting

### Symptom: container starts then exits, logs show `Missing info.json` / `Missing MongoDB server.jar`

**Cause:** Running a hand-built image without the proper build script artifacts.
**Solution:** Use the official `appsmith/appsmith-ce`/`-ee` images (or the documented multi-arch build script). These files are baked at build time.

### Symptom: `healthcheck.sh` reports a process not `RUNNING`

**Cause:** One supervised service (backend/editor/rts/db) failed to start — commonly the JVM OOM-killed, or an external DB URL is wrong.
**Solution:** `docker exec appsmith supervisorctl status` to find the failed program, then read its log under `/appsmith-stacks/logs/`. For the backend, check memory and `APPSMITH_JAVA_ARGS`; for DBs, verify connection URLs.

### Symptom: datasource credentials invalid after restart/upgrade

**Cause:** `APPSMITH_ENCRYPTION_PASSWORD`/`APPSMITH_ENCRYPTION_SALT` changed.
**Solution:** Restore the original values. If lost, credentials must be re-entered for every datasource.
**Prevention:** Pin these secrets permanently.

### Symptom: TLS not provisioning for a custom domain

**Cause:** DNS not pointing at the host, port 443 not published, or domain mismatch.
**Solution:** Confirm `APPSMITH_CUSTOM_DOMAIN`, publish 443, ensure A/AAAA records resolve to the host so Caddy can complete the ACME challenge.

### Symptom: large import or query fails with a payload/size error

**Cause:** Response/request exceeds the reactive codec limit or plugin cap.
**Solution:** Raise `APPSMITH_CODEC_SIZE` (MB) and/or `APPSMITH_PLUGIN_MAX_RESPONSE_SIZE_MB`; restart.

### Symptom: server slow / periodic restarts under load

**Cause:** JVM heap pressure inside the container.
**Solution:** Increase container memory and set `APPSMITH_JAVA_ARGS="-Xms<n> -Xmx<n>"`. Capture a heap dump (`record-heap-dump.sh`) if it recurs. Move page-load queries to return less data.

### Symptom: OAuth/Google redirect loop or mismatch

**Cause:** Redirect URI / domain not aligned with the deployed URL.
**Solution:** Set `APPSMITH_CUSTOM_DOMAIN` and `APPSMITH_OAUTH2_GOOGLE_REDIRECT_URI` to match, and register the redirect URI with the identity provider.

### Symptom: can't run more than one replica without data issues

**Cause:** Replicas using embedded DBs or a non-RWX volume.
**Solution:** Externalize MongoDB/PostgreSQL/Redis and use a `ReadWriteMany` volume (§5.2).

---

## 9. Developer Internals

### 9.1 Repository layout

```text
app/
  server/                      Java Spring WebFlux backend (Maven reactor)
    appsmith-server/           main app: controllers, services, domains, migrations, security
    appsmith-interfaces/       shared contracts (plugin SPI)
    appsmith-plugins/          25 datasource connector modules
    appsmith-git/              JGit-based Git operations
    reactive-caching/          reactive Redis cache abstraction
  client/                      React + Redux + Redux-Saga SPA (Yarn workspaces)
    src/
      api/, ce/api/, ee/api/   API client classes (extend base Api/API)
      sagas/, ce/sagas/        redux-saga side-effect orchestration
      workers/Evaluation/      sandboxed reactive evaluation engine
      workers/common/DependencyMap/  dependency graph
      plugins/Linting/         inline lint of bindings
      widgets/, widgets/wds/   classic + WDS widget families
      layoutSystems/           fixedlayout, autolayout, anvil
      pages/Editor/, pages/AppIDE/  the builder IDE
      ce/, ee/                 community vs enterprise split
    packages/
      rts/                     Node.js Real-Time Service (+ appsmithctl in src/ctl)
      ast/                     JS AST parsing
      design-system/           ads, ads-old, widgets, widgets-old, theming, headless
      dsl/                     page DSL transforms/migrations
deploy/
  docker/                      Dockerfile fs/, supervisord, Caddy, ops scripts, compose
  helm/                        Kubernetes chart
  ansible/, aws/, aws_ami/, digital_ocean/, heroku/, packer/
```

### 9.2 Request lifecycle (end to end)

```text
User action in editor/viewer
   → Redux action dispatched
   → watcher saga (takeLatest/takeEvery) forks a worker saga
   → worker `call`s an *Api client class
   → HTTP request to /api/v1/<resource>
   → Caddy → backend :8080
   → Spring WebFlux controller (@RequestMapping(Url.X)) returns Mono/Flux
   → reactive service layer → reactive Mongo/Redis or a plugin PluginExecutor (for datasource queries)
   → ResponseDTO serialized back
   → worker saga `put`s SUCCESS/ERROR action → Redux store updates
   → evaluation worker recomputes dependent bindings → React re-renders
```

### 9.3 The page DSL and migrations

An application's pages are stored as a **DSL** (a serializable widget tree). The `packages/dsl` module and `layoutSystems/common/DSLConversions` handle DSL transforms and **version migrations** so older apps keep working as the widget schema evolves. Server-side, `server/migrations` applies metadata-store schema migrations on boot.

### 9.4 Import/export internals

Applications serialize to a portable JSON via the `exports/` and `imports/` server packages (`exportable`/`importable` artifact model). This underpins app export/import, partial import/export, Git serialization, and the template gallery. Datasource secrets are excluded from exports by design.

### 9.5 Writing a new datasource plugin

To add a connector: create a new Maven module under `app/server/appsmith-plugins/`, declare it in the plugins POM, implement the `PluginExecutor` contract from `appsmith-interfaces` (connection build/test, action execution, datasource/template metadata), and provide the editor form config. The platform discovers and loads it like the 25 existing connectors — no changes to core controllers required.

---

## 10. Code Quality and Conventions

- **Reactive end to end (server).** Blocking calls are avoided in the WebFlux pipeline; data access uses reactive Mongo/Redis drivers. Reviewers should reject blocking I/O introduced into reactive flows.
- **CE/EE separation.** Both client and server use parallel `ce/`/`ee/` trees so enterprise code overlays community code without forking. New community features land in `ce/`; enterprise overrides extend them.
- **Saga-centric side effects (client).** Async logic lives in sagas, not components; components stay declarative and read from the Redux store. This keeps side effects testable and cancellable (`takeLatest`).
- **Typed contracts.** TypeScript across the client; the API client classes centralize endpoint definitions, so the REST surface has a single client-side source of truth per resource.
- **Heavy automated testing.** The client uses Cypress (`app/client/cypress`) and Playwright (`app/client/playwright`) for end-to-end coverage and Jest for unit tests; the server has extensive JUnit integration tests (`appsmith-server/src/test`), including DSL-migration and import/export fixtures.
- **Generators and templates.** The client includes scaffolding generators (`app/client/generators`) for new widgets, enforcing structural consistency across the large widget catalog.

> [!NOTE]
> AST-based static extraction yields little structured metadata for this stack (Java is not parsed by the extractor, and the TypeScript monorepo's barrel exports and decorator/registry patterns hide the real surface). The authoritative surfaces are the controller `@RequestMapping` constants (`UrlCE`), the plugin module list, the widget directory tree, and the `APPSMITH_*` env set — all enumerated directly from source in this guide.

---

## 11. Potential Improvements

These are observations for operators and contributors, derived from the codebase and the public issue tracker — not defects in your installation.

- **Complete the MongoDB → PostgreSQL migration.** Two metadata-store data paths and a suite of `pg-*`/`mongodb-fixer` scripts coexist during the transition. Operators on older instances should plan the migration; the dual-path code is extra surface area until retired.
- **Lighten the single-container footprint.** Bundling the editor, server, RTS, and three databases in one image is excellent for onboarding but heavy for production. Externalizing databases (already supported) should be the documented default for anything beyond evaluation.
- **Kubernetes log parsing.** The supervisord stdout prefix vs. Caddy access-log issue ([#41876](https://github.com/appsmithorg/appsmith/issues/41876)) is worth resolving for clean log pipelines.
- **Widget polish.** Tracked UX items include the required-marker rendering on Select widgets ([#41734](https://github.com/appsmithorg/appsmith/issues/41734)) and an editor dark mode ([#41858](https://github.com/appsmithorg/appsmith/issues/41858)).
- **Consolidate widget families.** The classic and **WDS/Anvil** widget sets overlap; converging them reduces maintenance and user confusion over which widget to use.

---

## 12. Contributing

- **Local development** (per the README and `contributions/CodeContributionsGuidelines.md`): run the client (`app/client`, Yarn 3 workspaces, Node 24) and server (`app/server`, Java 25 + Maven) separately for fast iteration, against local databases.
- **Code of Conduct and Contribution Guide** live at the repo root (`CODE_OF_CONDUCT.md`, `CONTRIBUTING.md`); server-specific guidelines under `contributions/ServerCodeContributionsGuidelines`.
- **Where things go:** new connectors → `appsmith-plugins/`; new widgets → `app/client/src/widgets/` (use the generator); community features → `ce/` trees; tests are expected (Cypress/Playwright/Jest client-side, JUnit server-side).
- **License:** Apache 2.0.

---

## 13. Quick Reference

### Supervised processes (inside the container)

| Program | Service | Port |
| --- | --- | --- |
| `editor` | Caddy v2 (routing, TLS, static client) | 80 / 443 |
| `backend` | Java Spring WebFlux server | 8080 |
| `rts` | Node.js Real-Time Service | 8091 |
| `postgres` | Embedded PostgreSQL | 5432 |
| `mongodb` | Embedded MongoDB | 27017 |
| `redis` | Embedded Redis | 6379 |

### Key paths (persistent volume)

| Path | Contents |
| --- | --- |
| `/appsmith-stacks/configuration/docker.env` | Rendered runtime config. |
| `/appsmith-stacks/data/` | Embedded database data. |
| `/appsmith-stacks/git-storage/` | Per-app Git working copies. |
| `/appsmith-stacks/logs/` | Process logs. |

### Essential commands

```bash
docker exec appsmith supervisorctl status        # process health
docker exec appsmith /opt/appsmith/healthcheck.sh # full health check
docker exec appsmith appsmithctl backup           # back up
docker exec appsmith appsmithctl restore          # restore
curl -fsS http://localhost:8080/api/v1/health     # server liveness (internal)
```

### Minimum production checklist

- [ ] `APPSMITH_ENCRYPTION_PASSWORD` / `APPSMITH_ENCRYPTION_SALT` set to fixed secrets and stored safely.
- [ ] External MongoDB/PostgreSQL/Redis configured; embedded DBs disabled.
- [ ] `ReadWriteMany` persistent volume for `/appsmith-stacks`; backups scheduled.
- [ ] TLS via custom domain (Caddy) or upstream Ingress; internal ports not exposed.
- [ ] SSO configured; `APPSMITH_SIGNUP_DISABLED` (or allowed-domains) set; form login disabled if SSO-only.
- [ ] `APPSMITH_ALLOWED_FRAME_ANCESTORS` tightened from the permissive default.
- [ ] JVM heap sized (`APPSMITH_JAVA_ARGS`); host memory adequate.
- [ ] Health probe wired into your orchestrator; pre-upgrade backup step in your runbook.

### API base

All REST endpoints are under `/api/v1/`. Health: `GET /api/v1/health`. See §2.4 for the resource map.

### Editions

| | CE (`appsmith-ce`) | EE (`appsmith-ee`) |
| --- | --- | --- |
| License | Apache 2.0 | Commercial (license key) |
| SSO | Google/GitHub/OIDC OAuth | + SAML / enterprise (Keycloak) |
| Access control | Core roles | Granular RBAC |
| Extras | — | Audit logs, business features, support |

---

_Generated June 2026 from appsmithorg/appsmith at 293e1b6. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
