Repository navigation
Implementation Plan: dokploy apply - Declarative YAML Config #4008
Copy link
Copy link
Open
Labels
enhancementNew feature or requestNew feature or request
Description
Summary
Implementation plan for dokploy apply -f dokploy.yaml — a declarative config command for the Dokploy CLI that enables managing Dokploy resources as code.
Related: #3872
High-Level Design
What it does
Users define their Dokploy infrastructure in a dokploy.yaml file and run dokploy apply -f dokploy.yaml to create or update resources on the server. This is the first step toward the full GitOps vision described in #3872.
YAML Schema (single project per file)
apiVersion: v1
kind: Project
name: my-project
description: "My project"
environments:
- name: production
applications:
- name: web-api
sourceType: github
buildType: dockerfile
repository: org/api-repo
branch: main
dockerfile: Dockerfile
replicas: 1
autoDeploy: true
domains:
- host: api.example.com
port: 3000
https: true
certificateType: letsencrypt
ports:
- publishedPort: 8080
targetPort: 3000
protocol: tcp
mounts:
- type: volume
mountPath: /data
volumeName: api-data
schedules:
- name: cleanup
cronExpression: "0 2 * * *"
command: "rm -rf /tmp/logs/*.log"
shellType: bash
compose:
- name: monitoring
sourceType: github
repository: org/monitoring
branch: main
composePath: ./docker-compose.yml
domains:
- host: grafana.example.com
port: 3000
serviceName: grafana
postgres:
- name: main-db
dockerImage: postgres:16
databaseName: myapp
databaseUser: admin
databasePassword: secure-password
mysql:
- name: mysql-db
dockerImage: mysql:8
databaseName: myapp
databaseUser: admin
databasePassword: pw
databaseRootPassword: root-pw
mariadb: [...]
mongo: [...]
redis: [...]Key Design Decisions
| Decision | Choice |
|---|---|
| Format | YAML |
| Scope per file | Single project |
| Reconciliation | Name-based matching, create/update only (no deletes) |
| Env vars | Managed separately via dokploy env push |
| Resource coverage | Applications, compose, all 5 DB types, domains, mounts, ports, redirects, security, schedules |
| Server targeting | Optional serverName field, resolved by name |
| CLI target | Added to existing Dokploy CLI |
CLI Interface
dokploy apply -f dokploy.yaml # Apply config
dokploy apply -f dokploy.yaml --dry-run # Preview changes
dokploy apply -f dokploy.yaml --verbose # Detailed outputArchitecture (new files in CLI repo)
src/
├── commands/apply.ts # oclif command entry point
├── lib/apply/
│ ├── parser.ts # YAML parsing + Zod validation
│ ├── schema.ts # Zod schema for dokploy.yaml
│ ├── types.ts # TypeScript types
│ ├── reconciler.ts # Orchestrates the full apply flow
│ ├── differ.ts # Compares YAML vs server state → plan
│ ├── executor.ts # Executes plan via API calls
│ ├── api-client.ts # Typed tRPC endpoint wrappers
│ └── reporter.ts # Terminal output formatting
Reconciliation Flow
- Parse & validate YAML against Zod schema (fail fast)
- Fetch all projects → find by name client-side (API is ID-based)
- For each environment → fetch or create by name
- For each resource → create (minimal fields) + update (remaining fields), or update if changed
- For each child resource (domains, ports, mounts, etc.) → match by unique key, create or update
Important implementation details:
- Name-based lookup is done client-side (no
findByNameAPI exists) - Resource creation is two-step: create with minimal fields, then update with full config
- Compose domains matched by
host+serviceName(not justhost) - If multiple resources share the same name → error out (name uniqueness not enforced in DB)
Implementation Steps
Phase 1: Foundation
- Set up project structure in CLI repo (
lib/apply/directory) - Define TypeScript types (
types.ts) - Build Zod validation schema (
schema.ts) - Build YAML parser with validation (
parser.ts)
Phase 2: API Client
- Build typed API client wrappers for all resource types (
api-client.ts)- Project: list, create
- Environment: list, create
- Application: list, create, update
- Compose: list, create, update
- Postgres/MySQL/MariaDB/Mongo/Redis: list, create, update
- Domain: list, create, update
- Port: list, create, update, delete
- Mount: list, create, update
- Redirect: list, create, update
- Security: list, create, update
- Schedule: list, create, update
Phase 3: Diff & Reconciliation
- Build differ (
differ.ts) — compare YAML config vs remote state, produce action plan - Build reconciler (
reconciler.ts) — orchestrate the flow in dependency order - Build executor (
executor.ts) — execute actions with error handling
Phase 4: CLI Command & Output
- Build reporter (
reporter.ts) — format plan and results for terminal - Build
applycommand (commands/apply.ts) — wire everything together with oclif flags - Implement
--dry-runmode (compute plan, print, skip execution)
Phase 5: Testing & Docs
- Unit tests for parser, differ, schema validation
- Integration tests against a Dokploy instance
- Update CLI README with
applycommand docs - Add example
dokploy.yamlfiles
Future Extensions (out of scope)
--pruneflag to delete resources not in YAMLdokploy exportto generate YAML from existing state- Organization-level resources (notifications, certificates, registries)
- Swarm-specific configuration block
- GitOps reconciliation controller (ArgoCD/Flux-style)
- Multi-file support (
dokploy apply -f dir/)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Activity
artur-pf commentedon Apr 5, 2026
would be extremely epic if this gets implemented
mcfdez commentedon Apr 8, 2026
I am ready to help with this implementation
Chathula commentedon Aug 15, 2026
Looking forward for this. Love to have shared app access through different environment.
As an example, DB instance is in shared environment, prod and staging environments can access it via different users we created.
dimeskigj commentedon Sep 8, 2026
I've been working on a Dokploy provider for Pulumi, I thought it would be helpful for some of the use-cases here: https://github.com/dimeskigj/pulumi-dokploy.
It's got basic coverage of the services Dokploy offers, and I've tested it on personal project and some of my company's smaller internal ones. Working on top of Pulumi helps, since we're not building an IaC tool from scratch.
Still have to iron out some kinks; I'd appreciate any contributions.
bernard-ng commentedon Oct 10, 2026
Hi everyone! I've been working on https://github.com/bernard-ng/dokploy-iac, a standalone CLI for managing Dokploy infrastructure through declarative YAML. It addresses several of the workflows discussed here, including importing an existing instance, previewing changes, and applying configuration.
It currently supports:
dokploy plan.dokploy apply --deploy.Once installed and connected to your instance, you can start in an empty directory:
The project is in beta and currently supports Dokploy 0.30.6 and 0.30.7. It uses its own workspace format and ships independently of the official Dokploy CLI.
I'd welcome feedback from people following this proposal, especially on the YAML structure, importing existing setups, and missing resource coverage. Bug reports and contributions are welcome!
feat: add declarative apply and export commands
pavliha commentedon Oct 12, 2026
The stale CLI PR (Dokploy/cli#30) is ported onto the new commander CLI as Dokploy/cli#60 and tested against a live server. It follows this plan, with three deviations I'd like a maintainer to confirm or reject before review:
databaseName,databaseUser,databasePasswordanddatabaseRootPasswordare sent on create and never diffed or updated afterwards.postgres.updatewith a new password only rewrites the stored value; the real change goes throughchangePassword(ALTER USER), so updating it from the file would make the dashboard and the database disagree.gitProvider: <name>on applications and compose, resolved by name likeserverName. Without it, GitHub-sourced services created byapplyhave nogithubIdand can't deploy.export(listed as a future extension here, but already in Exposing port has no effect #30) writes only fields the schema knows and never writes passwords, so the output is safe to commit.apply --verbosemasks passwords in diffs too.Everything else matches the plan: one project per file, name-based matching, create/update only, env vars managed separately.
feat: add declarative apply and export commands