This page covers what you need to know for managing Kong Konnect
resources using the kongctl declarative configuration approach.
For supported resource types and field-level resource definitions see the Declarative Resource Reference.
- Overview
- Quick Start
- Core Concepts
- Resource Types
- Configuration Structure
- Kongctl Metadata
- YAML Tags
- Commands Reference
- CI/CD Integration
- Best Practices
- Troubleshooting
kongctl's declarative management feature enables you to
manage your Kong Konnect resources with
simple YAML declaration files and a simple state free CLI tool.
- Configuration manifests: Configuration is expressed as simple YAML files that describe the desired state of your Konnect resources. Configuration files can be split into multiple files and directories for modularity and reuse.
- Plan-Based: Plans are objects that represent required changes to move a set of resources from one state to another, desired, state.
In
kongctl, plan artifacts are first class concepts that can be created, stored, reviewed, and applied. Plans are represented as JSON objects and can be generated and stored as files for later application. When running declarative commands, if plans are not provided they are generated implicitly and executed immediately. - State-Free:
kongctldoes not use a state file or database to store the current state. The system relies on querying of the online Konnect state in order to calculate plans and apply changes. - Namespace Support: Namespaces provide a way to isolate resources between teams and environments. Each resource can be assigned to a specific namespace, and resources in different namespaces are not considered when calculating plans or applying changes. Namespaces can be set at the resource level or inherited from file-level defaults.
- Kong Konnect Account: Sign up for free
kongctlinstalled: See installation instructions- Authenticated with Konnect: Run
kongctl login
Create a working directory:
mkdir kong-portal && cd kong-portalCreate a file named portal.yaml:
portals:
- ref: my-portal
name: "my-developer-portal"
display_name: "My Developer Portal"
description: "API documentation for developers"
authentication_enabled: false
default_api_visibility: "public"
default_page_visibility: "public"
apis:
- ref: users-api
name: "Users API"
description: "API for user management"
publications:
- ref: users-api-publication
portal_id: my-portalPreview changes:
kongctl diff -f portal.yamlApply configuration:
kongctl apply -f portal.yamlVerify resources with kongctl get commands:
kongctl get portalskongctl get apisYour developer portal and API are now live! Visit the Konnect Console to see your developer portal with the published API.
Resources have multiple identifiers:
- ref: Required field for each reference in declarative configuration.
refmust be unique across any loaded set of configuration files. - id: Most Konnect resources have an
idfield which is a Konnect assigned UUID. This field is not represented in declarative configuration files. - name: Many Konnect resources have a
namefield which may or may not be unique within an organization for that resource type.
application_auth_strategies:
- ref: oauth-strategy # ref identifies a resource within a configuration
name: "OAuth 2.0 Strategy" # Identifies an auth strategy within Konnect
portals:
- ref: developer-portal
name: "Developer Portal"
default_application_auth_strategy: oauth-strategy # References the auth strategy by it's ref valuePlans are central to how kongctl manages resources. Plans are objects which
define the required steps to move a set of resources from their current state to a
desired state. Plans can be created, stored, reviewed, and applied at a later time
and are stored as JSON files. Plans are not required to be used,
but can enable advanced workflows.
Both apply and sync commands use the planning engine internally:
Implicit Planning (direct execution):
# Internally generates plan and executes it
kongctl apply -f config.yamlExplicit Planning (two-phase execution):
# Phase 1: Generate plan artifact
kongctl plan -f config.yaml --output-file plan.json
# Phase 2: Execute plan artifact (can be done later)
kongctl apply --plan plan.jsonPlan artifacts enable more advanced workflows:
- Audit Trail: Store plans in version control alongside configurations
- Review Process: Share plans with team members before execution
- Deferred Execution: Generate plans in CI, apply them after approval
- Rollback Safety: Keep previously applied plans for rollback
- Compliance: Document exactly what changes were planned
kongctl aims to support all of the Kong Konnect resource types but each
resource requires specific handling and coding changes. The following
lists the currently supported resources and their relationships.
Parent Resources (support kongctl metadata):
- APIs
- Catalog Services
- Portals
- Application Auth Strategies
- Control Planes (including Control Plane Groups)
- Event Gateways
Child Resources (do NOT support kongctl metadata):
- API Versions
- API Publications
- API Implementations
- API Documents
- Portal Pages
- Portal Snippets
- Portal Customizations
- Portal Custom Domains
- Portal Email Configs
- Portal Email Templates
- Gateway Services
Note: Portal email domains are currently imperative-only because the Konnect API exposes them at the organization level without labels or namespace scoping. Use
kongctl get portal email-domainsto inspect them; declarative management will be added when Konnect supports namespacing or labels for these resources.
Portal email templates are customizable per portal. Apply mode creates/updates templates but will not delete any that already exist in Konnect; sync mode plans deletions for customized templates that are absent from the declarative configuration.
# Optional defaults section
_defaults:
kongctl: # kongctl metadata defaults
namespace: production
protected: false
portals: # List of portal resources
- ref: developer-portal # ref is required on all resources
name: "developer-portal"
display_name: "Developer Portal"
description: "API documentation hub"
kongctl: # kongctl metadata defined explicitly on resource
namespace: platform-prod
protected: trueParents are defined at the root of a configuration while children can be expressed both nested under their parent and at the root with a parent reference field.
Hierarchical Configuration:
apis:
- ref: users-api
name: "Users API"
versions:
- ref: v1
name: "v1.0.0"
spec: !file ./specs/users-v1.yaml
publications:
- ref: public
portal: main-portal
visibility: publicSeparate Configuration:
apis:
- ref: users-api
name: "Users API"
api_versions:
- ref: v1
api: users-api
name: "v1.0.0"
spec: !file ./specs/users-v1.yaml
api_publications:
- ref: public
api: users-api
portal: main-portalControl planes can represent Konnect control plane groups by setting their cluster type to "CLUSTER_TYPE_CONTROL_PLANE_GROUP". Group entries manage membership through the members array. Each member must resolve to the Konnect ID of a non-group control plane, so you can provide literal UUIDs or reference other declarative control planes with !ref.
control_planes:
- ref: shared-group
name: "shared-group"
cluster_type: "CLUSTER_TYPE_CONTROL_PLANE_GROUP"
members:
- id: !ref prod-us-runtime#id
- id: !ref prod-eu-runtime#idWhen you apply or sync this configuration, kongctl replaces the entire membership list in Konnect to match the declarative members block.
The kongctl section provides metadata for resource management.
This metadata is stored in Kong Konnect labels and labels are only
provided on parent resources. Thus, kongctl metadata is
only supported on parent resources.
The protected field prevents accidental deletion of critical resources:
portals:
- ref: production-portal
name: "Production Portal"
kongctl:
protected: true # Cannot be deleted until protection is removedThe namespace field enables multi-team resource isolation:
apis:
- ref: billing-api
name: "Billing API"
kongctl:
namespace: finance-team # Owned by finance team
protected: falseUse _defaults to set default values for all resources in a file:
_defaults:
kongctl:
namespace: platform-team
protected: true
portals:
- ref: api-portal
name: "API Portal"
# Inherits namespace: platform-team and protected: true
- ref: test-portal
name: "Test Portal"
kongctl:
namespace: qa-team
protected: false
# Overrides both defaultskongctl provides some default behavior depending on how metadata fields
are specified or omitted. The following tables summarize the behavior.
| File Default | Resource Value | Final Result | Notes |
|---|---|---|---|
| Not set | Not set | "default" | System default |
| Not set | "team-a" | "team-a" | Resource explicit |
| Not set | "" (empty) | ERROR | Empty namespace not allowed |
| "team-b" | Not set | "team-b" | Inherits default |
| "team-b" | "team-a" | "team-a" | Resource overrides |
| "team-b" | "" (empty) | ERROR | Empty namespace not allowed |
| "" (empty) | Any value | ERROR | Empty default not allowed |
| File Default | Resource Value | Final Result | Notes |
|---|---|---|---|
| Not set | Not set | false | System default |
| Not set | true | true | Resource explicit |
| Not set | false | false | Explicit false |
| true | Not set | true | Inherits default |
| true | false | false | Resource overrides |
| false | true | true | Resource overrides |
Child resources automatically inherit the namespace of their parent resource:
External resources (_external blocks) are references to Konnect objects that are managed elsewhere.
Because kongctl does not own those objects:
- External resources cannot declare
kongctlmetadata. Supplyingkongctl.namespaceorkongctl.protectedon an external resource results in a parsing error. File-level defaults are ignored for externals. - External references do not add their namespaces to sync planning. Only namespaces from managed parent resources are considered when sync mode calculates deletes.
- Child resources (portal pages, customizations, etc.) are still planned by resolving the external parent's Konnect ID.
Ensure the owning team labels the parent (for example via
kongctl adopt) so the ID can be resolved, but you do not need to (and cannot) assign a namespace to the external definition itself.
Deck integration is configured on control planes via the _deck pseudo-resource. kongctl runs deck once per
control plane that declares _deck, then resolves external gateway services by selector name. _external.requires.deck
is not supported.
control_planes:
- ref: prod-cp
name: "prod-cp"
_deck:
files:
- "kong.yaml"
flags:
- "--select-tag=kongctl"
gateway_services:
- ref: billing-gw
_external:
selector:
matchFields:
name: "billing-service"Notes:
_deckis allowed only on control planes and only one_deckconfig is allowed per control plane._deck.filesmust include at least one state file._deck.flagscan include additional deck flags (but not Konnect auth or output flags)._external.selector.matchFields.nameis required for external gateway services and must be the only selector field.- kongctl runs exactly one
deck gateway applyordeck gateway syncper control plane that declares_deck. - Deck state files should include
_info.select_tagsand matchingtagson entities sosyncdoes not delete resources owned by other deck files. kongctl does not inject select tags for you. - Relative deck file paths are resolved relative to the declarative config file and must remain within the
--base-dirboundary (default: the config file directory). - Plan files store deck base directories relative to the plan file location. When emitting a plan to stdout,
the base directory is made relative to the current working directory (use
--output-filefor portable plans). Applying a plan resolves them from the plan file directory (or the current working directory when using--plan -). kongctl plan/diffrunsdeck gateway diffto decide whether an external tool change is needed.kongctl applyrunsdeck gateway applyandkongctl syncrunsdeck gateway sync. For apply mode, deletes reported by deck diff are ignored.- If the control plane is being created in the same plan (or the ID is not available), kongctl skips deck diff and includes the external tool step.
- For gateway steps, kongctl injects Konnect auth flags and output flags (
--json-output --no-color); do not supply--konnect-token,--konnect-control-plane-name,--konnect-addr, or output flags yourself. - Plans represent deck resolution targets explicitly via
post_resolution_targetson the_deckchange entry, including control plane identifiers and the gateway service selector.
The kongctl plan command provides built-in namespace guardrails:
--require-any-namespaceforces every managed resource to declare a namespace viakongctl.namespaceor_defaults.kongctl.namespace.--require-namespace=<ns>restricts planning to the provided namespaces (repeat or comma-separate the flag to allow multiple values).
These flags help prevent accidentally operating on unexpected namespaces, especially when running in sync mode.
YAML tags are like preprocessors for YAML file data. They allow you to load content from external files, reference across resources and extract specific values from structured data. Over time more tags may be added to support various functions and use cases.
Load the entire content of a file as a string:
apis:
- ref: users-api
name: "Users API"
description: !file ./docs/api-description.mdSupported file types: Any text file (.txt, .md, .yaml, .json, etc.)
You can extract specific values from structured data loaded from the file tag
with this hash (#) notation:
apis:
- ref: users-api
name: !file ./specs/openapi.yaml#info.title # loads info.title field from the openapi.yaml file
description: !file ./specs/openapi.yaml#info.description
version: !file ./specs/openapi.yaml#info.version
versions:
- ref: v1
spec: !file ./specs/openapi.yamlAlternatively values can be extracted using this map format:
apis:
- ref: products-api
name: !file
path: ./specs/products.yaml
extract: info.title
labels:
contact: !file
path: ./specs/products.yaml
extract: info.contact.emailAll file paths are resolved relative to the directory containing the configuration file:
project/
├── config.yaml # Main config file
├── specs/
│ ├── users-api.yaml
│ └── products-api.yaml
└── docs/
└── descriptions.txt
In config.yaml:
apis:
- ref: users-api
name: !file ./specs/users-api.yaml#info.title
description: !file ./docs/descriptions.txtPath Traversal Prevention: Absolute paths are blocked. Relative paths may include
.., but the resolved path must stay within the base directory boundary. By default,
the boundary is the root of each -f source (file: its parent dir, dir: the directory itself).
For stdin, the boundary defaults to the current working directory. Set the base directory with
--base-dir or konnect.declarative.base-dir (KONGCTL_<PROFILE>_KONNECT_DECLARATIVE_BASE_DIR,
for example KONGCTL_DEFAULT_KONNECT_DECLARATIVE_BASE_DIR).
# ❌ These will fail with security errors
description: !file /etc/passwd
# ❌ This will fail if it resolves outside the base directory
config: !file ../../../sensitive/file.yaml
# ✅ These are allowed (if they stay within the base directory)
description: !file ../docs/description.txt
config: !file ./config/settings.yamlFile Size Limits: Files are limited to 10MB.
File Caching: Files are cached during a single execution to improve performance:
apis:
- ref: api-1
name: !file ./common.yaml#api.name # File loaded and cached
description: !file ./common.yaml#api.desc # Uses cached version
- ref: api-2
team: !file ./common.yaml#team.name # Uses cached versionThe following are high level descriptions of commands for declarative configuration management. See the command usage text for details on command usage, flags and options.
Create a plan - a JSON file containing the set of planned changes to a set of resources.
Plans are generated with either --mode apply or --mode sync which determines
whether resources missing from the input configuration are planned for deletion or not.
Generate an apply plan and output to STDOUT:
kongctl plan -f config.yaml --mode applyGenerate a sync plan and output to STDOUT:
kongctl plan -f config.yaml --mode syncApplying a configuration will create or update resources to match the desired state
and will not delete resources. Because apply does not delete resources, it can
be used for incremental application of resource configurations. For example, you could
apply a portal in one command and then later apply apis in a separate command. With
the sync command, this process is not possible as missing resources will be deleted.
Apply directly from config:
kongctl apply -f config.yamlApply from saved plan:
kongctl apply --plan plan.jsonPreview changes without applying:
kongctl apply -f config.yaml --dry-runsync applies a set of configurations including deleting resources
missing from the input configuration data.
Preview sync changes:
kongctl sync -f config.yaml --dry-runSync configuration with a prompt confirmation:
kongctl sync -f team-config.yamlSkip confirmation prompt (caution!):
kongctl sync -f config.yaml --auto-approveSync from a plan artifact:
kongctl sync --plan plan.jsonDisplay preview of changes between current and desired state:
Preview changes in apply mode (CREATE and UPDATE only):
kongctl diff -f config.yaml --mode applyPreview changes in sync mode (CREATE, UPDATE, and DELETE):
kongctl diff -f config.yaml --mode syncPreview targeted deletions in delete mode (DELETE only for matching resources):
kongctl diff -f config.yaml --mode deletePreview changes from a plan artifact:
kongctl diff --plan plan.jsonNote:
--modecannot be used with--planbecause mode is stored in the plan artifact metadata.
For UPDATE actions, text diff shows only the fields that would be
changed. JSON and YAML outputs expose the same detail in each change's
changed_fields object while keeping fields as the execution payload.
kongctl declarative configuration engine will only consider resources that
are part of the list of kongctl.namespace values given to it during planning
and execution of changes. There may be cases where you want to bring an
existing Konnect resource into configuration that was created outside of the
configuration management process. The adopt command enables you to
add the proper namespace label to an existing Konnect resources without
modifying any other fields. Once you adopt a resource, you need to add the
configuration for it
to your configuration set to ensure it is managed going forward.
Adopt a portal by name:
kongctl adopt portal my-portal --namespace team-alphaAdopt a control plane by ID:
kongctl adopt control-plane 22cd8a0b-72e7-4212-9099-0764f8e9c5ac \
--namespace platformIf the resource already has a KONGCTL-namespace label, the command fails
without making changes.
Export current Konnect resource state to various formats.
# Export all APIs with their child resources and include debug logging
# to tf-import format
kongctl dump tf-import --resources=api --include-child-resources# Export all portal and api resources to
# kongctl declarative configuration with format and the team-alpha namespace
kongctl dump declarative --resources=portal,api --default-namespace=team-alphaKey principles for CI/CD integration:
- Plan on PR: Generate and review plans in pull requests
- Apply on Merge: Apply reviewed plans when merged to target branch
- Environment Separation: Different configs for dev/staging/prod
- Approval Gates: Require human approval for production
Each team manages their own namespace:
# team-alpha/config.yaml
_defaults:
kongctl:
namespace: team-alpha
apis:
- ref: frontend-api
name: "Frontend API"
# Automatically in team-alpha namespaceUse configuration profiles for different environments:
# Development environment
kongctl apply -f config.yaml --profile dev
# Production environment
kongctl apply -f config.yaml --profile prod-
Protect production resources:
apis: - ref: payment-api kongctl: namespace: production protected: true
-
Use namespaces for isolation:
- One namespace per team
- Separate namespaces for environments
- Clear namespace ownership documentation
-
Version control everything:
- Configuration files
- OpenAPI specifications
- Documentation
-
Review plans before applying:
- Use
planin production - Save plans for audit trail
- Implement approval workflows
- Use
Developer creates plan:
kongctl plan -f config.yaml --output-file proposed-changes.jsonReview changes visually:
kongctl diff --plan proposed-changes.jsonShare plan for review (commit to git, attach to PR, etc.):
git add proposed-changes.json
git commit -m "Plan for adding new API endpoints"After approval, apply the plan:
kongctl apply --plan proposed-changes.json# CI/CD Pipeline Stage 1: Plan Generation
kongctl plan -f production-config.yaml \
--output-file plan-$(date +%Y%m%d-%H%M%S).json
# Stage 2: Manual approval gate
# - Plan artifact is stored as build artifact
# - Team reviews plan details
# - Approval triggers next stage
# Stage 3: Plan Execution
kongctl apply --plan plan-20240115-142530.json --auto-approveList recent plans (assuming you store them):
ls -la plans/Review what the previous state included:
kongctl diff --plan plans/last-known-good.jsonRevert to previous state:
kongctl sync --plan plans/last-known-good.json --auto-approve❌ Setting kongctl on child resources:
# WRONG
apis:
- ref: my-api
kongctl:
namespace: team-a
versions:
- ref: v1
kongctl: # ERROR - not supported on child resources
protected: true✅ Correct approach:
# RIGHT
apis:
- ref: my-api
kongctl:
namespace: team-a
protected: true
versions:
- ref: v1❌ Using name as identifier:
# WRONG - using display name
api_publications:
- ref: pub1
api: "Users API"✅ Use ref for references:
# RIGHT - using ref
api_publications:
- ref: pub1
api: users-apiKongctl uses strict YAML validation to catch configuration errors early:
# This will cause an error
portals:
- ref: my-portal
name: "My Portal"
lables: # ❌ ERROR: Unknown field 'lables'. Did you mean 'labels'?
team: platformCommon field name errors:
lables→labelsdescriptin→descriptiondisplayname→display_namestrategytype→strategy_type
Authentication Failures:
- Verify PAT is not expired
- Check authentication:
kongctl get me - Ensure proper credential storage
Plan Generation Failures:
- Validate YAML syntax
- Check file paths are correct
- Verify network connectivity
Apply Failures:
- Review plan for conflicts
- Check for protected resources
- Verify dependencies exist
File Loading Errors:
Error: failed to process file tag: file not found: ./specs/missing.yaml
- Verify the file path is correct
- Check that the file exists
- Ensure proper relative path from config file location
Enable verbose logging:
kongctl apply -f config.yaml --log-level debugEnable trace logging for HTTP requests:
kongctl apply -f config.yaml --log-level traceFor more troubleshooting help, see the Troubleshooting Guide.
Browse the examples directory
- Troubleshooting Guide - Common issues and solutions
- E2E Test Harness - How to run end-to-end tests locally and in CI
kongctl plan/applydiff the live Konnect state before deciding what action to schedule. The portal custom domain API only returns a subset of fields (hostname,enabled, verification method, CNAME status,skip_ca_check, timestamps). The raw certificate and private key are never returned.- Because the
UpdatePortalCustomDomainendpoint only patches theenabledflag, the planner emits anUPDATEchange when the desiredenabledvalue differs. Every other drift (hostname, verification method,skip_ca_check) is treated as an in-place replace:DELETEfollowed byCREATE. - Pure certificate rotations that keep the same verification method and
skip_ca_checksetting are invisible to the diff because Konnect does not echo those values. To force a replacement, temporarily change a detectable field (e.g., toggleskip_ca_checkor switch verification method), or remove the domain from configuration, apply, and then reintroduce it with the new certificate material.