This guide walks you through the process of creating and contributing Radius Resource Type definitions and Recipes to this repository.
Before you begin, ensure you have basic understanding of Radius concepts and the IaC languages you plan to use (Bicep or Terraform).
- Familiarize yourself with the Radius
- Familiarize yourself with the Resource Types tutorial
- Familiarize yourself with the Radius Recipes concept
Contributing a Resource Type and Recipe involves the following:
- Resource Type Definition: Defines the structure and properties of your Resource Type
- Recipes: Terraform or Bicep templates for deploying the Resource on different platforms
- Documentation: Providing clear usage examples and instructions
- Testing: Ensuring your Resource Type works as expected in a Radius Environment
- Submission: Creating a pull request with your changes
Radius Resource Types and Recipes are categorized into the three maturity levels detailed below. Contributions of Resource Types and Recipes may begin at the Alpha or Beta stage and progress through to the Stable phase.
Stage 1: Alpha
Purpose: Enable community members to contribute Resource Types and Recipes with minimal barriers
Audience: Developers/Contributors exploring new technologies or learning Radius
Requirements:
- Resource Type schema validation: YAML schema passes validation
- Single Recipe: At least one working Recipe for any cloud platform
- Basic documentation: README with usage examples
- Manual testing: Evidence of local testing by contributor
- Maintainer review: Formal review and approval by Radius maintainers
Stage 2: Beta
Purpose: Ensure contributions meet production-ready standards with comprehensive testing and documentation
Audience: Contributors seeking to have their Resource Types included in official Radius releases
Requirements:
- Multi-platform support: Recipes for all three platforms (AWS, Azure, and Kubernetes)
- IAC support: Recipes for both Bicep and Terraform
- Automated testing: Functional tests that validate the Resource Type and Recipes
- Documentation: Detailed README written for platform engineers describing Recipe behavior as well as developer documentation in the description fields of the Resource Type definition
- Ownership: Designated owner for the Resource Type and Recipe
- Maintainer review: Formal review and approval by Radius maintainers
Stage 3: Stable
Purpose: Establish Resource Types and Recipes as officially supported and maintained by the Radius project
Audience: Enterprise users doing production deployments and seeking stable, well-tested Resource Types and Recipes
Requirements:
- Functional tests have 100% coverage and results for Resource Type definition and Recipes
- Integration testing: Full integration with Radius CI/CD pipeline and release process
- Documentation: Well proven platform engineer and developer documentation
- Ownership (Resource Type and Kubernetes Recipes): Radius maintainers assume ownership of the Resource Type definition and Kubernetes Recipes
- Ownership (cloud platform Recipes): Contributor designates a committed owner for the cloud platform Recipes (e.g. AWS and Azure)
- SLA commitment: Defined support level and response time commitments from cloud platform Recipe owners
- Maintainer review: Formal review and approval by Radius maintainers
Identify the Resource Type you want to contribute. It could be a database, messaging service, or any other resource that fits within the Radius ecosystem. You can pick from the open issues in this repository or propose a new Resource Type.
Create a fork of the resource-types-contrib repository on GitHub, then clone your fork to your local machine:
git clone https://github.com/<your-username>/resource-types-contrib.gitCreate a new directory for your Resource Type under the appropriate category. For example if you are contributing a new redisCaches Resource Type, the directory structure should look like this:
resource-types-contrib/
└── Data/
└── redisCaches/
├── redisCaches.yaml
├── README.md
└── recipes/
├── aws-memorydb/
│ ├── bicep/
│ │ ├── memorydb.bicep
│ │ └── memorydb.params
│ └── terraform/
│ ├── main.tf
│ └── var.tf
├── azure-cache/
│ ├── bicep/
│ │ ├── azure-cache.bicep
│ │ └── azure-cache.params
│ └── terraform/
│ ├── main.tf
│ └── var.tf
└── kubernetes/
├── bicep/
│ ├── kubernetes-redis.bicep
│ └── kubernetes-redis.params
└── terraform/
├── main.tf
└── var.tf
For example, if you are contributing to a redisCaches Resource Type, create a redisCaches.yaml file that defines the redisCaches Resource Type. The initial version may look similar to:
namespace: Radius.Data
types:
redisCaches:
apiVersions:
'2025-08-01-preview':
schema:
type: object
properties:
environment:
type: string
application:
type: string
capacity:
type: string
enum: [S, M, L, XL]
host:
type: string
readOnly: true
port:
type: string
readOnly: true
username:
type: string
readOnly: true
secrets:
type: object
properties:
password:
type: string
readOnly: true
required:
- environment
- applicationThe following guidelines should be followed when contributing new Resource Types:
-
The
namespacefield follows the formatRadius.<Category>, where<Category>is a high-level grouping (e.g., Data, Dapr, AI). Some examples might beRadius.Data/*orRadius.Security/*. -
The Resource Type name follows the camelCase convention and is in plural form, such as
redisCaches,sqlDatabases, orrabbitMQQueues. -
Version should be the latest date and follow the format
YYYY-MM-DD-preview. This is the date on which the contribution is made or when the Resource Type is tested and validated, e.g.2025-07-20-preview. Once the Resource Types has reached the Stable maturity level, the-previewsuffix is removed. -
The description property must be populated with developer documentation. The top-level descrption and each property's description are output by
rad resource-type showand will be visible in the Radius Dashboard in the future. See documentation section for more details. -
Each Resource Type will have one or more common properties:
environmentmust always be a required property (include in therequiredproperty).applicationmay be a required or property:- Required: Use when a resource must always be part of an application. For example, a Container will always be part of an application.
- Not required: Do not include in the
requiredproperty for resources that may be deployed to an Environment without an application with the intention of being a shared resource. A blob store, for example, may be shared across multiple containers and applications.
-
Each additional properties must:
- Follow the camelCase naming convention.
- Include a description for each property (see documentation section for more details).
- Properties that are required must be listed in the
requiredblock. - Properties that are set by the Recipe only after the resource is deployed must be marked as
readOnly: true. - Have a
type. Valid types are:integer,string,object,enum, andarray. - Properties that contain sensitive data such as passwords, tokens, or keys must be marked with
x-radius-sensitive: true. This annotation can be applied to properties of typestringorobject. Radius will encrypt the data using theradius-encryption-keysecret and store it temporarily in the Radius data store; it will be deleted during deployment processing.
-
Resource Types are made for developers and must be application-oriented. Avoid infrastructure-specific or platform-specific properties. Make sure the schema is simple and intuitive, avoiding unnecessary complexity.
Each Resource Type has two types of documentation written specifically for developers, and separately, for platform engineers.
Developer documentation is embedded in the Resource Type definition. Each Resource Type definition must have documentation on how and when to use the resource in the top-level description property. When writing developer documentation, use Markdown. This is especially important for code blocks which must be quoted using triple backquotes. Output from rad resource-type show is shown in text only, but the Radius Dashboard formats the Markdown property including the ability to single-click copy code blocks.
Each property must also include:
- The overall description of the property including example values.
- Whether the property is required or optional.
When setting the description of properties:
- Unquoted strings are preferred, avoid special characters such as
:,{,},[,],,,&,*,#,?,|,-,<,>,=,!,%,@, and\. - Prefix the description with
(Required),(Optional), or(Read Only). - If an enum, do not add acceptable values in the description (these are visible in VS Code via Intellisense).
- There are no defaults for enums. If the Recipes should assume a value, denote that "the value is assumed to be _____".
- Denote values using
backquotes.
For example, the initial redisCaches Resource Type from above must be enhanced with developer documentation:
namespace: Radius.Data
types:
redisCaches:
description: |
The Radius.Data/redisCaches Resource Type adds a Redis cache to an application. Start by adding a redisCaches resource to your application definition Bicep file:
resource redis 'Radius.Data/redisCaches@2025-08-01-preview' = {
name: 'redis'
properties: {
application: todolist.id
environment: environment
capacity: 'M'
}
}
Then add a connection from a Container resource to the Redis resource.
resource myContainer 'Radius.Compute/containers@2025-08-01-preview' = {
name: 'myContainer'
properties: { ... }
connections: {
redis: {
source: redis.id
}
}
}
apiVersions:
'2025-08-01-preview':
schema:
type: object
properties:
environment:
type: string
description: (Required) The Radius Environment ID. Typically set by the rad CLI. Typically value should be `environment`.
application:
type: string
description: (Required) The Radius Application ID. `todolist.id` for example.
capacity:
type: string
enum: [S, M, L, XL]
description: (Optional) The capacity of the Redis cache.
host:
type: string
readOnly: true
description: (Read Only) The hostname used to connect to the Redis server.
port:
type: string
readOnly: true
description: (Read Only) The network port used to connect of the Redis server.
username:
type: string
readOnly: true
description: (Read Only) The username used to connect to Redis server.
secrets:
type: object
properties:
password:
type: string
readOnly: true
description: (Read Only) The password used to connect to the Redis server.
required:
- environment
- applicationDocumentation for platform engineers must be provided in a README.md file in the Resource Type directory. This README should focus on describing the Recipes and the requirements for building a custom Recipe for the Resource Type. This file should include:
## Overview
A brief description of the Resource Type and its purpose.
## Recipes
A list of available Recipes for this Resource Type, including links to the Bicep and Terraform templates.:
|Platform| IaC Language| Recipe Name | Stage |
|---|---|---|---|
| AWS | Bicep | aws-memorydb.bicep | Alpha |
| AWS | Terraform | aws-memorydb/main.tf | Alpha |
| Azure | Bicep | azure-cache.bicep | Alpha |
| Azure | Terraform | azure-cache/main.tf | Alpha |
| Kubernetes | Bicep | kubernetes-redis.bicep | Alpha |
| Kubernetes | Terraform | kubernetes/main.tf | Alpha |
## Recipe Input Properties
A list of properties set by developers and a description of their purpose when authoring a Recipe.
## Recipe Output Properties
A list of read-only properties which are required to be set by the Recipe.
Create a README.md file in each Recipe directory to provide specific instructions for using that Recipe. Include:
## Recipe Description
A brief description of what the Recipe does and how to use it.
## Usage Instructions
- Include overview of the Resource Type and its purpose
- Provide clear instructions for using the Resource Type and Recipes
- Document any special requirements or limitations
- Provide troubleshooting guidance
- Link to relevant external documentation
Radius supports Recipes in both Bicep and Terraform. Create a recipes directory under your Resource Type directory, and add platform-specific subdirectories for each IaC language you want to support.
- Familiarize yourself with the IaC language of your choice Bicep or Terraform
- Familiarize yourself with the Radius Recipe concept
- Follow this how-to guide to write your first Recipe, register your Recipe in the Environment
@description('Information about what resource is calling this Recipe. Generated by Radius. For more information visit https://docs.radapp.dev/operations/custom-recipes/')
param context object
extension kubernetes with {
kubeConfig: ''
namespace: context.runtime.kubernetes.namespace
} as kubernetes
resource redis 'apps/Deployment@v1' = {
metadata: {
name: 'redis-${uniqueString(context.resource.id)}'
}
spec: {
selector: {
matchLabels: {
app: 'redis'
resource: context.resource.name
}
}
template: {
metadata: {
labels: {
app: 'redis'
resource: context.resource.name
// Label pods with the Application name so `rad run` can find the logs.
'radapp.io/application': context.application == null ? '' : context.application.name
}
}
spec: {
containers: [
{
// This container is the running redis instance.
name: 'redis'
image: 'redis'
ports: [
{
containerPort: 6379
}
]
}
{
// This container will connect to redis and stream logs to stdout for aid in development.
name: 'redis-monitor'
image: 'redis'
args: [
'redis-cli'
'-h'
'localhost'
'MONITOR'
]
}
]
}
}
}
}
resource svc 'core/Service@v1' = {
metadata: {
name: 'redis-${uniqueString(context.resource.id)}'
}
spec: {
type: 'ClusterIP'
selector: {
app: 'redis'
resource: context.resource.name
}
ports: [
{
port: 6379
}
]
}
}
output result object = {
// This workaround is needed because the deployment engine omits Kubernetes resources from its output.
// This allows Kubernetes resources to be cleaned up when the resource is deleted.
// Once this gap is addressed, users won't need to do this.
resources: [
'/planes/kubernetes/local/namespaces/${svc.metadata.namespace}/providers/core/Service/${svc.metadata.name}'
'/planes/kubernetes/local/namespaces/${redis.metadata.namespace}/providers/apps/Deployment/${redis.metadata.name}'
]
values: {
host: '${svc.metadata.name}.${svc.metadata.namespace}.svc.cluster.local'
port: 6379
}
}terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = ">= 2.0"
}
}
}
variable "context" {
description = "Radius-provided object containing information about the resource calling the Recipe."
type = any
}
variable "port" {
description = "The port Redis is offered on. Defaults to 6379."
type = number
default = 6379
}
resource "kubernetes_deployment" "redis" {
metadata {
name = "redis-${sha512(var.context.resource.id)}"
namespace = var.context.runtime.kubernetes.namespace
labels = {
app = "redis"
}
}
spec {
selector {
match_labels = {
app = "redis"
resource = var.context.resource.name
}
}
template {
metadata {
labels = {
app = "redis"
resource = var.context.resource.name
}
}
spec {
container {
name = "redis"
image = "redis:6"
port {
container_port = 6379
}
}
}
}
}
}
resource "kubernetes_service" "redis" {
metadata {
name = "redis-${sha512(var.context.resource.id)}"
namespace = var.context.runtime.kubernetes.namespace
}
spec {
type = "ClusterIP"
selector = {
app = "redis"
resource = var.context.resource.name
}
port {
port = var.port
target_port = "6379"
}
}
}
output "result" {
value = {
values = {
host = "${kubernetes_service.metadata.name}.${kubernetes_service.metadata.namespace}.svc.cluster.local"
port = kubernetes_service.spec.port[0].port
username = ""
}
secrets = {
password = ""
}
// UCP resource IDs
resources = [
"/planes/kubernetes/local/namespaces/${kubernetes_service.metadata.namespace}/providers/core/Service/${kubernetes_service.metadata.name}",
"/planes/kubernetes/local/namespaces/${kubernetes_deployment.metadata.namespace}/providers/apps/Deployment/${kubernetes_deployment.metadata.name}"
]
}
description = "The result of the Recipe. Must match the target resource's schema."
sensitive = true
}
- Recipes should be idempotent, meaning they can be run multiple times without causing issues.
- Handle secure defaults for all parameters, especially those related to secrets.
- Recipes should handle different size/configuration options, allowing users to choose the appropriate configuration for their needs.
- Provide outputs required to connect to the resource provisioned by the Recipe.
- Use core Radius Resource Types like
containers,gatewayandsecretswhere applicable to ensure consistency and reusability. - Use comments to explain complex logic or important decisions in your Recipe code.
After creating your Resource Type and Recipes, test them locally using the provided make commands.
-
Set up your environment (one-time setup):
make install-radius-cli make create-radius-cluster
-
Build your Resource Type:
make build-resource-type TYPE_FOLDER=Data/redisCaches
-
Build your recipes:
# For Bicep recipes make build-bicep-recipe RECIPE_PATH=Data/redisCaches/recipes/kubernetes/bicep # For Terraform recipes make build-terraform-recipe RECIPE_PATH=Data/redisCaches/recipes/kubernetes/terraform
-
Register your recipes (required before testing):
# Register Bicep recipes you've built
make register RECIPE_TYPE=bicep
# Register Terraform recipes in a separate environment or after cleanup
make register RECIPE_TYPE=terraform ENVIRONMENT=my-terraform-envIf you rely on a single Radius environment, run the register → test flow for one IaC format, clean up (or switch environments), and only then repeat for the other format so the two template kinds do not overwrite each other's registrations.
-
Test individual recipes:
make test-recipe RECIPE_PATH=Data/redisCaches/recipes/kubernetes/bicep
-
Test all recipes (if you have multiple):
make testTo scope testing to a specific implementation, set RECIPE_TYPE to bicep or terraform (and optionally override the Radius environment with ENVIRONMENT):
make test RECIPE_TYPE=bicep
make test RECIPE_TYPE=terraform ENVIRONMENT=my-terraform-envRemember that make test assumes recipes are already registered. To validate both Bicep and Terraform recipes for the same resource type, run those register/test cycles sequentially or in distinct environments to avoid template registration conflicts.
For detailed testing instructions, see Testing Resource Types and Recipes.
For resource types categorized in the "Stable" maturity level, automated test coverage is required in the repository's CI/CD pipeline. The contribution guide with the steps to follow to update the automated tests can be found in Contributing Tests for Stable Resource Types