DevOps Dictionary

Kubernetes Custom Resource Definition (CRD)

Kubernetes Custom Resource Definition (CRD) is a Kubernetes API extension that lets you define your own resource types. A CRD, short for Custom Resource Definition, allows teams to manage custom objects with the same declarative workflow they use for built-in Kubernetes resources like Pods, Services, Deployments, and ConfigMaps.

In practical terms, a CRD lets you teach Kubernetes about a new kind of object. For example, a platform team might define a Database, BackupPolicy, Application, or KafkaTopic resource, then let engineers create and update those objects using YAML, kubectl, GitOps, or CI/CD pipelines.

What a CRD does

A CRD adds a new resource type to the Kubernetes API server. Once installed, users can create custom resources based on that definition.

For example, after installing a CRD for a Database resource, a developer could apply a manifest like this:

apiVersion: platform.example.com/v1
kind: Database
metadata:
  name: orders-db
spec:
  engine: postgres
  version: "15"
  storageGB: 100

Kubernetes stores the custom resource, validates it based on the CRD schema, and exposes it through the API. By itself, the CRD only defines and stores the object. To make something happen, such as creating a real database, you usually pair it with a controller or operator.

How CRDs work

A CRD defines the shape and behavior of a custom Kubernetes resource. It tells the Kubernetes API server:

  • Group: The API group, such as platform.example.com.
  • Version: The API version, such as v1alpha1, v1beta1, or v1.
  • Kind: The resource type name, such as Database or Application.
  • Plural name: The collection name used by the API, such as databases.
  • Scope: Whether the resource is namespaced or cluster-wide.
  • Schema: The allowed fields and data types under spec, status, and other sections.

After the CRD is applied to the cluster, Kubernetes serves a new API endpoint for that custom resource. You can then use standard Kubernetes tools to interact with it:

kubectl get databases
kubectl describe database orders-db
kubectl apply -f database.yaml
kubectl delete database orders-db

CRDs and controllers

A CRD defines the desired state. A controller acts on that desired state.

For example, a custom Database resource might describe a PostgreSQL database that should exist. A controller watches for Database objects and reconciles the real infrastructure to match the requested state. It might create a cloud database, configure users, rotate credentials, and update the resource status when the database is ready.

This pattern is common in Kubernetes operators. The CRD gives users a Kubernetes-native API. The controller contains the operational logic.

Common use cases

  • Operators: Tools like Prometheus Operator, cert-manager, and External Secrets Operator use CRDs to expose domain-specific resources.
  • Platform APIs: Platform teams use CRDs to provide internal resources like Application, Environment, Database, or Queue.
  • Infrastructure management: Tools such as Crossplane use CRDs to model cloud infrastructure as Kubernetes resources. For example, you can define AWS resources through Kubernetes, as shown in this guide to deploy AWS resources using Crossplane on Kubernetes.
  • GitOps workflows: Custom resources can live in Git and be applied by tools like Argo CD or Flux.
  • Policy and security: Admission controllers, policy engines, and security tools often define CRDs for rules, constraints, and reports.

Simple real-world example

Suppose your startup runs multiple services, and each service needs a standard deployment setup: a Kubernetes Deployment, Service, Ingress, autoscaling rules, monitoring labels, and default resource requests.

Instead of asking every team to copy and maintain several YAML files, your platform team could create an Application CRD:

apiVersion: platform.example.com/v1
kind: Application
metadata:
  name: payments-api
spec:
  image: ghcr.io/example/payments-api:1.8.2
  replicas: 3
  port: 8080
  ingress:
    host: payments.example.com

A controller can read this custom resource and create the required Kubernetes objects behind the scenes. Developers get a simpler interface, while the platform team keeps control over defaults, naming, security settings, and operational standards.

Key parts of a CRD

  • spec: The desired state provided by the user. For example, requested database size, image version, or retention policy.
  • status: The observed state reported by a controller. For example, Ready, Failed, endpoint URLs, or last sync time.
  • OpenAPI schema: Defines valid fields, types, required values, defaults, and validation rules.
  • Versions: Allow the API to evolve over time, such as moving from v1alpha1 to v1.
  • Subresources: Optional API features such as /status and /scale.
  • Additional printer columns: Custom fields shown in kubectl get output.

Benefits of CRDs

  • Kubernetes-native workflow: Teams can use kubectl, YAML, RBAC, audit logs, admission policies, and GitOps with custom resource types.
  • Declarative APIs: Users describe the desired state instead of running imperative scripts.
  • Platform abstraction: Platform teams can hide complex implementation details behind a simpler API.
  • Consistent operations: Controllers can enforce standard patterns across teams and environments.
  • Extensibility: Teams can model resources that Kubernetes does not include by default.

Tradeoffs and limitations

  • A CRD does not run logic by itself: Without a controller, Kubernetes stores and validates the custom resource, but no external action happens.
  • API design matters: Poorly designed fields, names, or versioning can create long-term migration problems.
  • Controllers add operational responsibility: You need to deploy, monitor, upgrade, and debug the controller code.
  • Validation has limits: CRD schemas catch many invalid inputs, but complex business rules often need admission webhooks or controller-side checks.
  • Too many CRDs can add complexity: A cluster with many operators and custom APIs can become harder to understand and upgrade.

CRD vs Custom Resource

A CRD is the definition of a custom resource type. A custom resource is an instance of that type.

For example:

  • Database CRD: Defines the Database API type.
  • orders-db custom resource: A specific Database object created from that CRD.

This is similar to how a built-in Kubernetes resource type works. Deployment is the resource type, while payments-api might be a specific Deployment object.

CRD vs Kubernetes API aggregation

CRDs are the most common way to extend the Kubernetes API because they are simpler to create and operate. Kubernetes API aggregation is a more advanced extension mechanism that lets you run a separate API server and integrate it with the main Kubernetes API.

Use CRDs when you need to define custom resources with standard Kubernetes API behavior. Consider API aggregation only when CRDs cannot support your needs, such as custom storage behavior or highly specialized API semantics.

CRDs in infrastructure workflows

CRDs are widely used in infrastructure automation because they let teams represent cloud and platform resources as Kubernetes objects. Crossplane is a common example. It uses CRDs to define resources such as databases, networks, IAM roles, and managed services, then reconciles them against cloud provider APIs.

This approach can fit teams that already use Kubernetes as a control plane. For a practical example, see how teams can deploy a Kubernetes app with an AWS resource using Crossplane.

CRDs and Terraform

CRDs and Terraform can both manage infrastructure-related state, but they work differently.

  • CRDs: Store desired state in the Kubernetes API and rely on controllers to reconcile continuously.
  • Terraform: Plans and applies changes through a separate workflow, usually with a state file or remote state backend.

Some teams use both. For example, Terraform might create the cluster and baseline infrastructure, while CRDs manage application-level resources inside the cluster. If you are comparing workflows, this guide on how to deploy Kubernetes resources using Terraform gives useful context.

Operational considerations

Before introducing a CRD into production, review these points:

  • Versioning: Plan how you will migrate users between API versions.
  • Validation: Define a strict schema so bad input fails early.
  • RBAC: Decide who can create, update, delete, and read custom resources.
  • Status reporting: Make controllers write clear status conditions so users can debug problems with kubectl describe.
  • Backups: Include custom resources in cluster backup and restore plans.
  • Upgrade testing: Test CRDs and controllers before Kubernetes version upgrades. CRDs can affect API behavior, admission paths, and dependent workloads. For upgrade planning, see these practical tips for Kubernetes upgrades.

When to use a CRD

Use a CRD when you want to expose a stable, declarative API inside Kubernetes for a resource that your team needs to manage repeatedly.

A CRD is a good fit when:

  • You want users to manage a resource with kubectl or GitOps.
  • You need Kubernetes RBAC, audit logs, and admission controls around that resource.
  • You plan to build or install a controller that reconciles the custom resource.
  • You want to standardize a platform workflow across teams.

A CRD may be a poor fit when a simple ConfigMap, Helm values file, CI/CD variable, or Terraform module would be easier to operate. If the custom API will only be used once or has no controller behind it, a CRD can add unnecessary complexity.

Summary

A Kubernetes CRD extends the Kubernetes API with a custom resource type. It lets teams define their own declarative APIs and manage them using standard Kubernetes workflows. CRDs are especially useful for operators, platform engineering, GitOps, and infrastructure automation, but they work best when paired with clear API design, strong validation, and a reliable controller.

A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
Y
X
Z