Kestra
Audited from github.com/kestra-io/kestra
Kestra is an open-source event-driven orchestration and scheduling platform for data and infrastructure pipelines, built on Java and Micronaut with a pluggable JDBC persistence layer (H2, MySQL, or PostgreSQL) that also serves as the message queue, plus a separate Vue 3 web UI.
- Language
- Java
- Database
- PostgreSQL
- Hosting
- Docker
- License
- Apache-2.0
- Running for
- 4 years
- Team
- 6-20 people
Why this architecture
Queueing and repository storage run through the same JDBC layer instead of a dedicated broker, so one PostgreSQL (or MySQL/H2) instance is enough to run the scheduler, executor, and worker modules together, while those modules stay separately buildable and scalable.
Tech stack by layer
9 technologies · audited Sep 17, 2026- MicronautApplication framework for every JVM module (core, webserver, scheduler, executor, worker), running on Netty.
- jOOQTyped SQL layer shared by the H2, MySQL, and Postgres JDBC modules for the repository and queue implementations.
- PebbleTemplating engine used for rendering flow variables and expressions.
- PostgreSQLRecommended production backend for the repository, queue, and storage metadata, via the jdbc-postgres module.
- MySQLAlternative JDBC backend for the same repository/queue abstraction as Postgres.
- H2Embedded JDBC backend used for local development and the executor/scheduler test suites.
Kestra architecture diagram
Open SVGDiagram as text
- Web UI (Vue · Vite) → webserver (Micronaut · Netty): REST
- API & triggers (REST · webhooks) → webserver (Micronaut · Netty): REST
- webserver (Micronaut · Netty) → Repository & queue (Postgres / MySQL / H2 (jOOQ)): flows · executions
- scheduler (schedules · triggers) → Repository & queue (Postgres / MySQL / H2 (jOOQ)): enqueue runs
- executor (flow orchestration) → Repository & queue (Postgres / MySQL / H2 (jOOQ)): queue
- worker (task runners · plugins) → Repository & queue (Postgres / MySQL / H2 (jOOQ)): results
Key architectural decisions
6 decisions- 01
Repository, queue, and storage metadata all run through one pluggable JDBC layer
jdbc/build.gradle defines the shared queue/repository abstraction, and jdbc-h2, jdbc-mysql, and jdbc-postgres each implement it via io.micronaut.sql:micronaut-jooq plus their own JDBC driver, so a single relational database can serve as the message queue and metadata store without a separate broker.
- 02
Runtime execution is split into dedicated modules instead of one process
The Gradle multi-project build has separate scheduler, executor, worker, worker-controller, and indexer modules (each with its own build.gradle), all depending on core and jdbc, so scheduling, task dispatch, and task execution can be scaled or deployed independently of each other.
- 03
A shared platform module enforces one set of dependency versions across all modules
Root build.gradle applies annotationProcessor/implementation/api enforcedPlatform(project(":platform")) to every subproject in the allprojects block, keeping the ~20 Gradle modules (core, jdbc-*, queue, scheduler, executor, worker, webserver, cli, …) on consistent library versions.
- 04
Docker images are built as a thin app layer on top of a shared base image
Dockerfile starts from ARG BASE_IMAGE="ghcr.io/kestra-io/kestra-base:latest-slim" and only copies in the docker/ runtime scripts and a plugins/ directory, while Dockerfile.base presumably builds that shared base separately, keeping plugin/runtime updates decoupled from the base JVM image.
- 05
The default compose setup points repository and queue config at one Postgres instance
docker-compose.yml configures KESTRA_CONFIGURATION with repository.type: postgres and queue.type: postgres against the same postgres service, so
docker compose upruns the whole platform (server standalone mode) off a single database container. - 06
The web UI is a separate Vue 3 + Vite SPA, not server-rendered from the JVM backend
ui/ has its own package-lock.json, vite.config.js, vitest.config.js, and .storybook directory, building independently of the Gradle backend modules and being served as static assets rather than through a JVM templating engine.
How Kestra is built
How Kestra is structured
Kestra is a Gradle multi-project build (settings.gradle) with roughly twenty JVM modules under one root build.gradle: model and core hold the domain model and engine logic; webserver, scheduler, executor, worker, and worker-controller are the runtime services; jdbc, jdbc-h2, jdbc-mysql, jdbc-postgres, and queue/queue-jdbc form the pluggable persistence and queueing layer; repository-memory and runner-memory provide in-memory implementations for testing; cli wraps everything into the io.kestra.cli.Kestra application entry point (mainClassName in build.gradle); and platform is a version-alignment module applied via enforcedPlatform across every other module. ui/ is a separate Vue 3 + TypeScript single-page app with its own package-lock.json and Vite/Vitest/Storybook config, versioned in the same repository but built independently of the Gradle backend. charts/kestra and charts/kestra-starter hold Helm charts for Kubernetes deployment.
Frontend
The ui/ directory is a standalone Vue application: ui/vite.config.js configures the Vite build, ui/vitest.config.js/ui/vitest.config.unit.js configure test running, and ui/.storybook documents UI components in isolation. The language breakdown (Vue at roughly 3.1M bytes, plus TypeScript and SCSS) confirms Vue 3 with TypeScript and SCSS styling rather than plain CSS. The UI is packaged and versioned in-repo but depends on npm (ui/package-lock.json) rather than the monorepo's Gradle toolchain, and talks to the Java backend over HTTP as a client of the webserver module's API.
Backend & APIs
Every backend module builds on Micronaut: core/build.gradle depends on io.micronaut:micronaut-http-server-netty (Netty as the HTTP layer) and io.micronaut.data:micronaut-data-model, and the JDBC modules add io.micronaut.sql:micronaut-jooq for typed SQL. core also pulls in Reactor (io.projectreactor:reactor-core) for reactive execution, Pebble (io.pebbletemplates:pebble) for flow templating, Caffeine for in-memory caching, and Jackson's Ion dataformat for serialization. Execution responsibilities are split across modules rather than one service: scheduler triggers flows, executor coordinates task execution, worker/worker-controller run tasks, and indexer builds search indexes — each is its own Gradle module depending on core, jdbc, and queue. The cli module assembles these into the single Kestra application class that the Docker image runs.
Data & persistence
Kestra abstracts its repository (flow/execution metadata) and queue behind a shared jdbc/queue-jdbc interface, implemented three ways: jdbc-postgres (runtimeOnly("org.postgresql:postgresql")), jdbc-mysql (runtimeOnly("com.mysql:mysql-connector-j")), and jdbc-h2 (runtimeOnly("com.h2database:h2")) for embedded/dev use, all built on io.micronaut.sql:micronaut-jooq. docker-compose.yml demonstrates the production-shaped default: a single postgres:18 container backs repository.type: postgres, queue.type: postgres, and local disk (storage.type: local) simultaneously, so Kestra does not require a separate Kafka or RabbitMQ broker to run in standalone mode.
Build, test & deploy
The JVM side builds and tests with Gradle (gradlew, gradle.properties, Java 25 toolchain declared in the root build.gradle), using JaCoCo for coverage aggregation (jacoco-report-aggregation plugin), SonarQube for static analysis, and an OWASP dependency-check plugin (owasp-dependency-suppressions.xml) for vulnerability scanning. jmh-benchmarks/build.gradle is a dedicated module for JMH microbenchmarks. .github/workflows (not individually enumerated in the facts gather but present in the tree) drives CI; .pinact.yaml and .github/dependabot.yml manage pinned/updated Action and dependency versions. Dockerfile.pr suggests a distinct build path for PR-triggered image builds, separate from the main Dockerfile/Dockerfile.base release pair.
Self-hosting notes
docker-compose.yml is the quickest self-host path: it runs kestra/kestra:latest in server standalone mode (command: server standalone) alongside a postgres:18 container, mounting the Docker socket (/var/run/docker.sock) so Kestra can launch task containers, and exposing the web UI/API on port 8080 (with an optional, unauthenticated-by-default management port 8081 commented out). The Dockerfile builds the distributed image as a thin layer — copying docker/ runtime scripts and a plugins/ directory — on top of ghcr.io/kestra-io/kestra-base:latest-slim, so plugin and application updates do not require rebuilding the full base JVM image. For Kubernetes, charts/kestra and charts/kestra-starter provide two Helm chart options of differing scope.
What to copy (and what not to)
Implementing the message queue on top of the same relational database used for the repository (via queue-jdbc plus per-database modules) is a strong pattern for any orchestration or workflow tool that wants a low-dependency "single Postgres instance" deployment story, at the cost of the queue module needing custom polling/locking logic instead of a purpose-built broker's delivery guarantees. Splitting scheduler, executor, and worker into separate Gradle modules — even though they can all run in one JVM via server standalone — pays off once an operator needs to scale workers independently from the scheduler; a smaller single-tenant tool would not need that many modules from day one. Enforcing one dependency-version platform (platform module via enforcedPlatform) across ~20 Gradle subprojects is worth copying for any multi-module JVM monorepo to avoid version drift between modules that must interoperate at runtime.
Sources & repo audit
- Audited
- Sep 17, 2026
- Commit
- 2765958
- License
- Apache-2.0
- build.gradle (root multi-module Gradle build, Java 25 toolchain)
- core/build.gradle (Micronaut, Netty, Pebble, Reactor)
- jdbc-postgres/build.gradle, jdbc-mysql/build.gradle, jdbc-h2/build.gradle (pluggable JDBC backends)
- docker-compose.yml (standalone server, Postgres-backed repository/queue)
- Dockerfile (base-image layering)
Independent analysis of repository at github.com/kestra-io/kestra. Spotted an inaccuracy? Use the claim form to request a correction.
Show this stack on your README or website
[](https://stackitfast.com/project/kestra)Paste it into your README. It shows your current stack and links to this page.
Scaffold it with your agent
Paste this prompt into Claude Code, Cursor, Windsurf or AGY to start a project with Kestra's architecture.
- 1Copy the promptThe full markdown spec, with every layer and decision.
- 2Open your AI toolClaude Code, Cursor, Windsurf or Copilot, in a new repo.
- 3Paste and scaffoldUse it as the first instruction; review before you ship.
# MISSION: Scaffold "Kestra" Production Architecture
You are an expert Senior Staff Software Architect and Full-Stack Engineer. Your mission is to scaffold and implement a production-grade, highly reliable, and modular codebase following the proven architecture of **Kestra**.
---
## 1. PROJECT SPECIFICATIONS & BENCHMARK
- **Reference Architecture**: Kestra
- **What It Does**: Kestra is an open-source event-driven orchestration and scheduling platform for data and infrastructure pipelines, built on Java and Micronaut with a pluggable JDBC persistence layer (H2, MySQL, or PostgreSQL) that also serves as the message queue, plus a separate Vue 3 web UI.
- **Domain & Category**: Declarative Orchestration & Data Flow Engine
- **Production Scale**: 6-20 people
- **Development Mode**: CLASSIC
- **Architectural Rationale**: Queueing and repository storage run through the same JDBC layer instead of a dedicated broker, so one PostgreSQL (or MySQL/H2) instance is enough to run the scheduler, executor, and worker modules together, while those modules stay separately buildable and scalable.
- **Live Website Reference**: https://kestra.io
- **Source Repository**: https://github.com/kestra-io/kestra
---
## 2. PRODUCTION TECH STACK
- **Full Stack Array**: Java, Micronaut, Vue, TypeScript, PostgreSQL, MySQL, H2, Docker, Helm
- **Primary Language(s)**: Java, TypeScript, Vue, JavaScript
- **License of the reference repo**: Apache-2.0
- **Frontend**: Vue — Web UI for authoring flows, viewing executions, and managing the instance, built as a standalone SPA under ui/.; Vite — Dev server and bundler for the ui/ Vue application.; Storybook — Component development and documentation for the UI, configured under ui/.storybook.
- **Backend & APIs**: Micronaut — Application framework for every JVM module (core, webserver, scheduler, executor, worker), running on Netty.; jOOQ — Typed SQL layer shared by the H2, MySQL, and Postgres JDBC modules for the repository and queue implementations.; Pebble — Templating engine used for rendering flow variables and expressions.
- **Data & persistence**: PostgreSQL — Recommended production backend for the repository, queue, and storage metadata, via the jdbc-postgres module.; MySQL — Alternative JDBC backend for the same repository/queue abstraction as Postgres.; H2 — Embedded JDBC backend used for local development and the executor/scheduler test suites.
- **Infrastructure & deploy**: Docker — Runtime image is built in two layers: a shared kestra-base image plus this thin app layer that copies in plugins.; Helm — Kubernetes charts for a full Kestra deployment and a lighter "starter" variant.
---
## 3. KEY ARCHITECTURAL DECISIONS (audited from https://github.com/kestra-io/kestra @ 2765958)
1. **Repository, queue, and storage metadata all run through one pluggable JDBC layer**: jdbc/build.gradle defines the shared queue/repository abstraction, and jdbc-h2, jdbc-mysql, and jdbc-postgres each implement it via io.micronaut.sql:micronaut-jooq plus their own JDBC driver, so a single relational database can serve as the message queue and metadata store without a separate broker.
2. **Runtime execution is split into dedicated modules instead of one process**: The Gradle multi-project build has separate scheduler, executor, worker, worker-controller, and indexer modules (each with its own build.gradle), all depending on core and jdbc, so scheduling, task dispatch, and task execution can be scaled or deployed independently of each other.
3. **A shared platform module enforces one set of dependency versions across all modules**: Root build.gradle applies annotationProcessor/implementation/api enforcedPlatform(project(":platform")) to every subproject in the allprojects block, keeping the ~20 Gradle modules (core, jdbc-*, queue, scheduler, executor, worker, webserver, cli, …) on consistent library versions.
4. **Docker images are built as a thin app layer on top of a shared base image**: Dockerfile starts from ARG BASE_IMAGE="ghcr.io/kestra-io/kestra-base:latest-slim" and only copies in the docker/ runtime scripts and a plugins/ directory, while Dockerfile.base presumably builds that shared base separately, keeping plugin/runtime updates decoupled from the base JVM image.
5. **The default compose setup points repository and queue config at one Postgres instance**: docker-compose.yml configures KESTRA_CONFIGURATION with repository.type: postgres and queue.type: postgres against the same postgres service, so `docker compose up` runs the whole platform (server standalone mode) off a single database container.
6. **The web UI is a separate Vue 3 + Vite SPA, not server-rendered from the JVM backend**: ui/ has its own package-lock.json, vite.config.js, vitest.config.js, and .storybook directory, building independently of the Gradle backend modules and being served as static assets rather than through a JVM templating engine.
---
## 4. NON-NEGOTIABLE ARCHITECTURAL GUARDRAILS
1. **Monorepo & Modular Separation**:
- Structure as a Turborepo monorepo with strict package boundaries:
- `apps/web`: Application UI, routing, layouts, and server endpoints.
- `packages/ui`: Shared design tokens, CSS variables, and Radix UI primitive components.
- `packages/db`: Database schemas, client singleton, declarative migrations, and seed scripts.
- `packages/config`: Shared TypeScript, ESLint, and build configurations.
2. **Strict Type Safety & Zero `any` Policy**:
- Enable `strict: true`, `noImplicitAny: true`, and `strictNullChecks: true`.
- Validate ALL external inputs, API request bodies, and query parameters with **Zod** schemas before execution.
3. **Frontend & Rendering Guidelines**:
- Isolate interactive UI state to leaf components. Keep core pages lightweight and performant.
4. **Design System & Aesthetics**:
- Keep every color, radius, shadow and font in a single token file (CSS variables) and consume tokens everywhere; never hardcode hex values in components.
- Prefer crisp 1px borders and one subtle shadow scale over blurry default shadows. Pair one sans-serif for body/headings with one monospace for tags, badges, metrics, and code.
5. **Data Layer & Reliability**:
- Write declarative schema definitions with foreign keys, composite indexes on queried filters, and automated timestamp triggers.
- Use connection pooling and prepared statements for serverless database execution.
---
## 5. STEP-BY-STEP SCAFFOLDING ROADMAP
- **Phase 1: Workspace & Root Config**: Initialize package manager, monorepo configuration (`turbo.json`, `tsconfig.base.json`, `package.json`).
- **Phase 2: Database Schema & Client**: Set up the data layer (PostgreSQL, MySQL, H2): client, connection pool, models, and migration scripts.
- **Phase 3: Design Tokens & UI Primitives**: Build accessible `Button`, `Input`, `Card`, `Badge`, and layout wrappers inside `packages/ui`.
- **Phase 4: Core Application Routes & Handlers**: Implement primary authentication, user session handling, and application routes.
- **Phase 5: Quality Assurance & Build Verification**: Run `tsc --noEmit`, ESLint, Prettier, and smoke test suites to ensure zero compilation or runtime errors.
---
## 6. EXECUTION INSTRUCTIONS
1. Review all specifications, architectural guardrails, and stack choices above.
2. Present the full monorepo directory tree structure.
3. Systematically generate the complete, production-ready codebase according to the 5-phase roadmap above — starting with the root workspace setup, followed by the database schema, UI design system package, and full-stack application routes until the repository is fully scaffolded and ready to run.Frequently asked about Kestra
What is Kestra built with?
The backend is Java on Micronaut/Netty, split into scheduler, executor, worker, and webserver Gradle modules that share a pluggable JDBC persistence layer (H2, MySQL, or PostgreSQL via jOOQ); the UI is a separate Vue 3 + Vite single-page app.
Does Kestra need a backend?
Kestra is the backend: the JVM modules (webserver, scheduler, executor, worker) are the orchestration engine itself, and the ui/ Vue app is a client of the webserver API rather than a standalone product.
Can I self-host Kestra?
Yes. docker-compose.yml runs a single kestra/kestra container in "server standalone" mode against a Postgres container, and charts/kestra plus charts/kestra-starter provide Helm charts for Kubernetes deployments.
Does Kestra require Kafka or a separate message broker?
No. The queue-jdbc and jdbc-postgres/jdbc-mysql/jdbc-h2 modules implement the queue abstraction directly on top of the relational database (queue.type: postgres in docker-compose.yml), so the same Postgres/MySQL/H2 instance backing the repository also serves as the queue.
Does Kestra have a UI?
Yes, ui/ is a Vue 3 single-page app built with Vite (ui/vite.config.js) and documented with Storybook (ui/.storybook), served as static assets rather than rendered by the Java backend.
One email a month: new deep dives and stack trends
New source-audited architectures, head-to-head comparisons and the monthly stack report. No spam, unsubscribe anytime.
Similar architectures
- n8nHybridFair-Code Workflow Automation & AI Integrator · 20+ peopleShares TypeScript · Vue · PostgreSQL
- NextcloudClassicSelf-Hosted Collaborative Productivity Suite · 20+ peopleShares TypeScript · Vue · MySQL
- MetabaseClassicBusiness Intelligence Platform · 20+ peopleShares TypeScript · Java · PostgreSQL
- GiteaClassicLightweight Self-Hosted Git Service · 20+ peopleShares TypeScript · Vue · PostgreSQL
- NocoDBHybridSmart Database Spreadsheet · 6-20 peopleShares TypeScript · Vue · PostgreSQL
- PrismaClassicNext-Generation Node.js & TypeScript ORM · 1M+ MAUShares TypeScript · PostgreSQL · MySQL