Skip to content

Implementation Plan: dokploy apply - Declarative YAML Config #4008

Open

Description

@nurikk

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 output

Architecture (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

  1. Parse & validate YAML against Zod schema (fail fast)
  2. Fetch all projects → find by name client-side (API is ID-based)
  3. For each environment → fetch or create by name
  4. For each resource → create (minimal fields) + update (remaining fields), or update if changed
  5. 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 findByName API exists)
  • Resource creation is two-step: create with minimal fields, then update with full config
  • Compose domains matched by host + serviceName (not just host)
  • 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 apply command (commands/apply.ts) — wire everything together with oclif flags
  • Implement --dry-run mode (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 apply command docs
  • Add example dokploy.yaml files

Future Extensions (out of scope)

  • --prune flag to delete resources not in YAML
  • dokploy export to 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/)

Activity

  1. artur-pf commented on Apr 5, 2026

    @artur-pf

    would be extremely epic if this gets implemented

  2. mcfdez commented on Apr 8, 2026

    @mcfdez
    Contributor

    I am ready to help with this implementation

  3. Chathula commented on Aug 15, 2026

    @Chathula

    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.

  4. dimeskigj commented on Sep 8, 2026

    @dimeskigj

    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.

  5. bernard-ng commented on Oct 10, 2026

    @bernard-ng

    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:

    • Importing instance settings, projects, services, domains, and environment variables into a local workspace.
    • Reviewing proposed changes with dokploy plan.
    • Applying configuration and deploying workloads with dokploy apply --deploy.
    • Detecting configuration drift and recreating the declared setup on a fresh Dokploy installation.

    Once installed and connected to your instance, you can start in an empty directory:

    dokploy import all
    dokploy plan
    dokploy apply --deploy

    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!

  6. pavliha commented on Oct 12, 2026

    @pavliha

    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:

    1. Database credentials are create-only. databaseName, databaseUser, databasePassword and databaseRootPassword are sent on create and never diffed or updated afterwards. postgres.update with a new password only rewrites the stored value; the real change goes through changePassword (ALTER USER), so updating it from the file would make the dashboard and the database disagree.
    2. gitProvider: <name> on applications and compose, resolved by name like serverName. Without it, GitHub-sourced services created by apply have no githubId and can't deploy.
    3. 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 --verbose masks passwords in diffs too.

    Everything else matches the plan: one project per file, name-based matching, create/update only, env vars managed separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions