Kubernetes is evolving fast, and one of the biggest changes in recent years has been the move from annotations to Custom Resource Definitions (CRDs) for configuration and extensibility.

This shift is especially visible in ingress configuration, where CRDs are taking over to provide better structure, validation, and scalability. The Kubernetes Gateway API, built entirely on CRDs, is emerging as the successor to the traditional Ingress API with a more expressive, role-
oriented approach to traffic management.

If you’re working with Kubernetes, understanding this transition matters. While annotations still have their place, CRDs are increasingly the go-to approach for extending Kubernetes. Let’s dig into why this is happening and what it means for your deployments.

Understanding annotations and CRDs

Before we get into the benefits of CRDs, let’s clarify what annotations and CRDs actually do in Kubernetes.
Annotations: Lightweight metadata
Annotations in Kubernetes are simple key-value pairs you can attach to objects like Pods, Services, and Ingresses. They let you store metadata that Kubernetes itself doesn’t interpret, but external tools can use.
Common uses for annotations:
● Attaching build information (commit hashes, version numbers)
● Enabling integrations with monitoring and logging tools
● Providing extra metadata for auditing and debugging
● Configuring ingress controllers (like nginx.ingress.kubernetes.io/rewrite-target)
Annotations are flexible and easy to implement, but they lack validation and structure. That makes them prone to errors when configurations get complex.

Example: Using Annotations in an Ingress Resource

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
 name: example-ingress
 annotations:
   haproxy.org/rewrites: "/* /index.html"
spec:
  rules:
      - host: example.com
        http:
          paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: example-service
                  port:
                     number: 80

CRDs: Extending Kubernetes with custom resources

Custom Resource Definitions (CRDs) let you define new resource types in Kubernetes. Once you create a CRD, Kubernetes treats it as a native resource that you can manage via kubectl and the Kubernetes API.
Common Use Cases for CRDs:
● Defining new resource types (like VirtualServer for NGINX, IngressRoute for Traefik)
● Automating complex workflows with Kubernetes Operators
● Enforcing policies with tools like Gatekeeper and Kyverno
● Managing application-specific configurations (e.g., database clusters, CI/CD pipelines)
Unlike annotations, CRDs provide schema validation and full API integration. That makes them much more robust for managing configurations and custom resources.

Example: Defining a Custom CRD for an HAProxy Backend

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: backends.haproxy.org
spec:
  group: haproxy.org
  names:
    kind: Backend
    plural: backends
    singular: backend
  scope: Namespaced
  versions:
    - name: v1alpha1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                servers:
                  type: array
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                      address:
                        type: string
                      port:
                        type: integer

Why Kubernetes is moving toward CRDs

Several key advantages drive the transition from annotations to CRDs:
1. Structured configuration vs. free-form metadata
Annotations are simple key-value pairs. That flexibility comes at a cost. They’re unstructured, which can lead to misconfigurations, especially in complex scenarios like ingress routing.
CRDs define structured, schema-driven configurations that provide:
● Hierarchical and easy-to-read YAML definitions
● Clear relationships between configuration elements
● Consistent formatting across teams and deployments
2. Validation and error prevention
One major problem with annotations is the lack of validation. A simple typo in an annotation key can cause silent failures. CRDs enforce schemas through OpenAPI validation, catching incorrect configurations before they’re applied. This improves reliability and cuts down troubleshooting time. It’s also much safer because validation happens before values get stored in Kubernetes.
3. Feature completeness and extensibility
Annotations were never designed for complex configurations. Using multiple annotations to define a single feature is error-prone and hard to maintain. CRDs let ingress controllers and other Kubernetes extensions expose their full feature sets natively. CRDs don’t just enable these advanced features, they also make them simpler to deploy, more versatile, and less prone to configuration errors.
For example, CRDs enable advanced ingress configurations like:
● Traffic splitting and canary deployments
● Rate limiting and session stickiness
● Multi-protocol support (e.g., TCP, UDP)
4. Versioning and upgradability
Annotations lack built-in versioning, making it hard to track changes or migrate configurations.
CRDs support versioning natively within the Kubernetes API, which allows:
● Backward compatibility between versions
● Controlled introduction of breaking changes
● Easier upgrades without disrupting existing workloads
5. Observability and debugging
Since annotations are embedded within existing resources, tracking their impact can be difficult. There’s also limited tooling for debugging annotation-based configurations. With CRDs, resources are independent objects, making them easier to observe, debug, and manage. You can:
● Query CRD-based configurations directly using kubectl
● Monitor CRD-backed resources in dashboards and logs
● Apply role-based access control (RBAC) specifically to CRD objects

Case study: Ingress configuration

Ingress controllers show Kubernetes’ shift from annotations to CRDs in action. Initially, annotations were the main way to configure ingress controllers. But as ingress features got more complex, managing configurations via annotations became increasingly difficult.
Many ingress controllers now provide CRD-based configurations. For example, HAProxy utilizes Backend, Defaults, and Global CRDs for fine-grained traffic management and configuration. These CRDs offer better validation, organization, and feature exposure compared with
annotation-based ingress configurations.
Challenges of CRDs
Despite their advantages, CRDs come with some trade-offs:
● Increased Complexity: Defining CRDs requires schema creation and, in some cases, custom controllers.
● Learning Curve: Teams used to annotations may need training on CRD best practices.
● Operational Overhead: Managing CRDs can introduce extra administrative tasks, especially in multi-cluster environments.

That said, as CRDs become more common, tooling and best practices are improving to make adoption easier.

The future of Kubernetes configuration

The Kubernetes ecosystem is increasingly favoring CRDs for extensibility. Many core Kubernetes tools and third-party projects are moving away from annotations for configuration and adopting CRDs instead.

This trend is likely to continue as:
● More Kubernetes-native projects embrace CRDs
● Community standards emerge for CRD usage
● The Kubernetes API evolves to support CRD-based workflows better

The Gateway API is a prime example of this evolution, offering a more expressive, extensible, and role-oriented approach to traffic management that is built entirely on CRDs, signifying a major step forward for Kubernetes networking.

Easing the transition with dual-mode controllers

As Gateway API adoption grows, the community is developing tools to make migration easier. One interesting approach is the emergence of controllers that support both Ingress and Gateway API simultaneously in a single deployment. For example, HAProxy Unified Gateway is planning to add this dual-mode capability to its open-source controller in 2026, letting organizations run both standards side-by-side while they gradually migrate routing rules. This kind of unified approach addresses one of the biggest pain points in the transition: having to manage separate controllers or do a risky “big bang” migration. It’s a practical solution that reduces operational overhead during the transition period, and we’ll likely see more projects adopt similar strategies as Gateway API becomes the standard.

What this means for you

Here’s what you should consider:
● Evaluate your current setup: Review your existing use of annotations and consider migrating to CRDs where it makes sense
● Invest in education: Upskill your team on CRD best practices
● Assess your tooling: Make sure you have good support for managing CRDs effectively in production

Annotations remain useful for lightweight metadata, but CRDs are clearly the future for structured, scalable, and robust Kubernetes configurations. Embracing CRDs now will help your team stay ahead of best practices and build more reliable, maintainable infrastructure.

Editor’s note: The code in this article was generated by AI and validated.