docs Export & Import

Export & Import

Export your instance's configuration as YAML to review it in git, clone it to another server, or rebuild after losing a host.

Overview

DeployKit can describe your whole instance — or a single project — as a YAML manifest. Keep it in git to review infrastructure changes, apply it on a new host to clone the setup, or use it to restore after losing a server. Exports are deterministic: keys are sorted, so re-exporting an unchanged instance produces an identical file and git diffs show only real changes.

This is configuration, not data. Database contents, volumes and game worlds are not included — use database backups for those.

Two files: configuration and secrets

Configuration manifest

kind: deploykit/instance-config

Projects, members (by email), applications, databases, Compose stacks with their Compose files, domains, env vars, scheduled tasks, backup schedules and status page settings. Credentials are withheld and listed by name only. Safe to commit to a private repository.

Secrets file

kind: deploykit/instance-secrets

The withheld values, in plain text: secret env vars and build args, database passwords, repository access tokens, per-app webhook secrets and sensitive stack mount files. Only produced when you ask for it. Never commit it.

yaml
version: 1
kind: deploykit/instance-config
exportedAt: "2026-10-14T10:00:00.000Z"
projects:
  - name: shop
    applications:
      - name: storefront
        sourceType: github
        repositoryUrl: https://github.com/acme/storefront
        branch: main
        buildType: nixpacks
        port: 3000
        env:
          NODE_ENV: production
          API_BASE_URL: https://api.acme.com
        withheldSecrets:
          - STRIPE_SECRET_KEY
          - sourceToken
        domains:
          - domain: shop.acme.com
            port: 3000
            https: true

What counts as a secret

Env vars are withheld from the configuration file when any of these match:

  • The name contains PASS, PWD, SECRET, TOKEN, KEY, CRED, PRIVATE, SALT, SIGNING, CIPHER or DSN
  • The value looks like a credential: a URL with user:password@, a PEM private key, a JWT, or a known token prefix (ghp_, sk_, xoxb-, AKIA…, glpat-, and others)
  • The value looks generated: 32+ characters, no spaces, and at least three character classes

Names ending in _URL, _HOST or _ENDPOINT stay in the manifest unless the value itself carries credentials — they are exactly what you want to review. Database passwords, repository tokens, webhook secrets, sensitive build args and stack mount contents are always withheld.

Review before you push: the configuration file still contains every Compose file and the name of every env var. The detection is deliberately broad, but check the file before committing it to a public repository.

Never exported

  • Servers and SSH keys — resources reference servers by name
  • The GitHub App — its credentials belong to the instance and its webhook URL. Applications carry their GitHub repository id, and the import re-links them to a matching installation on the target
  • Users — members are matched by email on import; users are never created
  • Game servers, notification channels and alert rules
  • Runtime state: container status and ids, deployment history, maintenance mode, preview environments, and the last run of each task

Exporting from the dashboard

  • Whole instance (admins): Settings → Configuration export and import → “Export configuration” downloads deploykit-config-<date>.yaml; “Export secrets” downloads deploykit-secrets-<date>.yaml
  • One project (project operators and admins): the “Export” button on the project page downloads that project's configuration, without secrets

If a value cannot be decrypted (for example after an ENCRYPTION_KEY change), it is skipped and listed under the export's warnings. Every export is recorded in the audit log as config.export.

Importing

Admins import from Settings → Configuration export and import → Import:

  • “Choose manifest” and, optionally, “Choose secrets file”
  • Optionally tick “Run on the local host when a server named in the file does not exist here”
  • Click Preview to see the plan — nothing is written yet
  • Click Import to apply exactly that plan

The plan lists every item as to create, already there, skipped (with a reason, such as an unknown member email) or blocking. Any blocking error disables Import: the import runs as a single transaction, because half a restore is worse than none. The plan also shows warnings, withheld values with nothing to restore, and container name conflicts.

Conflict behaviour

An import creates what is missing and never modifies what already exists. Resources are matched by name (case-insensitive):

  • Existing project — kept as is, but its contents are still walked: re-applying a manifest after adding an app creates just that app
  • Existing application, database or stack — left untouched, including its domains, env vars and tasks. Adding a domain or cron job to something that already runs is a change, not a missing resource
  • Domain already routed on this instance — skipped
  • Two existing projects (or servers) with the same name — blocking error until you rename one
  • Status page slug already in use — the project is imported with its status page disabled
  • Server named in the file does not exist — blocking error by default, or the resource runs on the local host if you ticked the option
  • Missing database password — a new one is generated (warning: anything holding the old connection string must be updated)
  • Applications linked to a GitHub App — re-linked to the one installation here that can see the repository; otherwise they fall back to their repository URL with a warning

Container name conflicts: containers are named dk-<name> after the resource, and a deploy replaces any container that already has that name. If the plan reports a conflict, deploying the imported resource would replace the existing one — rename one of them first.

After importing

Nothing is deployed: the import writes configuration, not containers. Imported applications and stacks wait for a Deploy, and imported databases for their first Start. Scheduled tasks and database backup schedules are registered immediately. Each applied import is recorded in the audit log as config.import.

Using the API

There is no CLI command for export or import; script it through the API instead. All three procedures are mutations (POST), so responses that may contain secrets are never cached.

bash
# Export the instance (admin). Returns { manifest, secrets, warnings, counts };
# manifest and secrets are YAML strings (secrets is null unless requested).
curl -s https://deploy.example.com/trpc/config.exportInstance \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"includeSecrets":false}'

# Export one project (project operator or admin)
curl -s https://deploy.example.com/trpc/config.exportProject \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"projectId":"<project-uuid>","includeSecrets":false}'

# Import (admin). dryRun defaults to true and returns the plan;
# send the same request with "dryRun": false to apply it.
curl -s https://deploy.example.com/trpc/config.import \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  -d "$(jq -n --rawfile m deploykit-config.yaml --rawfile s deploykit-secrets.yaml \
        '{manifest: $m, secrets: $s, dryRun: true, onMissingServer: "fail"}')"

onMissingServer is "fail" (default) or "local". Limits: 2 MB for the manifest and 500 KB for the secrets file.