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.
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.
A CRD defines the shape and behavior of a custom Kubernetes resource. It tells the Kubernetes API server:
platform.example.com.v1alpha1, v1beta1, or v1.Database or Application.databases.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
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.
Application, Environment, Database, or Queue.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.
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.v1alpha1 to v1./status and /scale.kubectl get output.kubectl, YAML, RBAC, audit logs, admission policies, and GitOps with custom resource types.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.
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 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 can both manage infrastructure-related state, but they work differently.
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.
Before introducing a CRD into production, review these points:
kubectl describe.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:
kubectl or GitOps.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.
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.