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 ace/(community) vs.ee/(enterprise) split throughout both client and server. This guide centers on CE and flags EE-only surfaces.
Table of Contents
- Executive Summary
- Architecture
- Requirements
- Configuration Mastery
- Deployment
- Security
- Operations
- Troubleshooting
- Developer Internals
- Code Quality and Conventions
- Potential Improvements
- Contributing
- 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-stackscontains 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_PASSWORDandAPPSMITH_ENCRYPTION_SALTencrypt 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.
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
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-apiendpoint 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, andINLINE_RUNTIME_CHUNK(seen inapp/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 theAPPSMITH_*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_ANCESTORSdefaults 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
applicationConfigschema 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:
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:
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:
StatefulSetby default (workload.kind); switches toDeploymentwhen autoscaling is enabled. Defaultimage.repository: appsmith/appsmith-ee, taglatest. - Persistence: PVC with
ReadWriteMany,10Gi,Retainreclaim 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(defaultClusterIP, port 80) and optionalIngress(classnginx, TLS via cert-manager/self-signed/custom secrets). - Scaling: HPA (
autoscaling) or KEDA (keda), mutually exclusive;PodDisruptionBudgetenabled withminAvailable: 1. - Resources: default requests
cpu: 500m,memory: 3000Mi. - Config:
applicationConfigmap ofAPPSMITH_*vars, or reference an existing secret viasecretName. Custom CA certs viacustomCAcert.
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_URLat shared, managed databases, and use aReadWriteManyvolume 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 existingSecret) rather than inlineapplicationConfig, 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 withAPPSMITH_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/:8091ports. - Lock down
APPSMITH_ALLOWED_FRAME_ANCESTORSto prevent clickjacking unless you intentionally embed apps. - Keep
APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX=falseso 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(setsecurityContext.runAsNonRoot/runAsUseron 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) 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.
# 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
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
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)
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 ince/; 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
@RequestMappingconstants (UrlCE), the plugin module list, the widget directory tree, and theAPPSMITH_*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-fixerscripts 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) is worth resolving for clean log pipelines.
- Widget polish. Tracked UX items include the required-marker rendering on Select widgets (#41734) and an editor dark mode (#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 undercontributions/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
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_SALTset to fixed secrets and stored safely. - [ ] External MongoDB/PostgreSQL/Redis configured; embedded DBs disabled.
- [ ]
ReadWriteManypersistent 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_ANCESTORStightened 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 |