Loading...
Loading...
Model cloud-native applications with Radius using Bicep. Use when asked to create an application definition, scaffold app.bicep, configure environments, or create custom resource types.
npx skill4agent add kachawla/radius-skills application-modelingPlatform-Engineering-Constitution.mdrad workspace showrad environment listrad recipe listrad resource-type listrad runCreate an application definitionCreate app.bicepScaffold a Radius applicationenv.bicepenvironment.bicepshared-resources.bicepexistingapp.bicepenv.bicepshared-resources.bicepexistingDockerfileContainerfileApplications.Core/containersRadius.Compute/containersEXPOSEDockerfilelistennginx.confRadius.AI/agentsRadius.AI/agents.enableObservabilityapp.bicepbicepconfig.jsonexistingApplications.Core/containersRadius.Compute/containerssrc/web/Dockerfilefrontend-uiEXPOSEtruefalseparam agentPrompt stringprompt: agentPromptapp.bicepApplications.Core/containersRadius.AI/agentsReshrahim/customer-agentradius/env.bicepradius/shared-resources.bicepexistingradius/app.bicepsrc/web/DockerfileApplications.Core/containersfrontend-uisrc/agent-runtime/app.pyRadius.AI/agentscontoso-dbcontoso-knowledge-basefrontend-uifrontend-uisrc/web/Dockerfile30003000src/web/nginx.conf3000src/agent-runtime/DockerfileRadius.AI/agentsgpt-4.1-miniparamapp.bicepbicepconfig.json{
"extensions": {
"radius": "br:biceptypes.azurecr.io/radius:latest",
"aws": "br:biceptypes.azurecr.io/aws:latest"
},
"experimentalFeaturesEnabled": {
"extensibility": true,
"dynamicTypeLoading": true
}
}Radius.*radius-resource-types{
"extensions": {
"radius": "br:biceptypes.azurecr.io/radius:latest",
"aws": "br:biceptypes.azurecr.io/aws:latest",
"radiusCompute": "radius-compute.tgz",
"radiusData": "radius-data.tgz",
"radiusStorage": "radius-storage.tgz",
"radiusSecurity": "radius-security.tgz",
"radiusAi": "radius-ai.tgz"
},
"experimentalFeaturesEnabled": {
"extensibility": true,
"dynamicTypeLoading": true
}
}rad bicep publish-extension --from-file <manifest.yaml> --target <output.tgz>Applications.*Applications.Core/containers| Type | Description |
|---|---|
| Application grouping |
| Container workloads (directly managed) |
| HTTP ingress gateways |
| Redis (recipe-based) |
| SQL databases (recipe-based) |
Radius.*Radius.Compute/containers| Type | Description |
|---|---|
| Container workloads (recipe-based) |
| Persistent storage volumes |
| HTTP routing (requires Gateway API controller) |
| MySQL databases |
| PostgreSQL databases |
| Blob/object storage |
| Secret stores |
| LLM-powered agent runtimes |
Radius.Data/redisCachesradius-resource-typesCritical difference:is directly managed by Radius.Applications.Core/containersis recipe-based — it needs a registered recipe to deploy.Radius.Compute/containers
Applications.*extension radius
param environment string
param application string
resource frontend 'Applications.Core/containers@2023-10-01-preview' = {
name: 'frontend'
properties: {
application: application
container: { // singular "container"
image: 'myregistry/frontend:latest'
ports: {
web: { containerPort: 3000 }
}
}
connections: {
database: { source: db.id }
}
}
}
resource db 'Applications.Datastores/sqlDatabases@2023-10-01-preview' = {
name: 'database'
properties: {
environment: environment
application: application
}
}Radius.*extension radius
extension radiusCompute
extension radiusData
param environment string
param application string
resource frontend 'Radius.Compute/containers@2025-08-01-preview' = {
name: 'frontend'
properties: {
environment: environment
application: application
containers: { // plural "containers" — a map!
frontend: {
image: 'myregistry/frontend:latest'
ports: {
web: { containerPort: 3000 }
}
}
}
connections: {
database: { source: db.id }
}
}
}
resource db 'Radius.Data/postgreSqlDatabases@2025-08-01-preview' = {
name: 'database'
properties: {
environment: environment
application: application
size: 'S' // Required if recipe expects it
}
}Schema difference:usesApplications.Core/containers(singular object).containerusesRadius.Compute/containers(plural map where each key is a container name).containers
Applications.Core/containersCONNECTION_<NAME>_HOST
CONNECTION_<NAME>_PORT
CONNECTION_<NAME>_DATABASE
CONNECTION_<NAME>_USERNAME
CONNECTION_<NAME>_PASSWORDRadius.Compute/containersCONNECTION_<NAME>_PROPERTIES={"host":"...","port":"...","database":"..."}
CONNECTION_<NAME>_ID=<resource-id>
CONNECTION_<NAME>_NAME=<connection-name>
CONNECTION_<NAME>_TYPE=<resource-type>CONNECTION_<NAME>_PROPERTIES// Go
func getConnProp(connName, prop string) string {
propsJSON := os.Getenv("CONNECTION_" + connName + "_PROPERTIES")
if propsJSON != "" {
var props map[string]interface{}
if err := json.Unmarshal([]byte(propsJSON), &props); err == nil {
if val, ok := props[strings.ToLower(prop)]; ok {
return fmt.Sprintf("%v", val)
}
}
}
return os.Getenv("CONNECTION_" + connName + "_" + prop)
}// Node.js
function getConnProp(connName, prop) {
const propsJson = process.env[`CONNECTION_${connName}_PROPERTIES`];
if (propsJson) {
try {
const props = JSON.parse(propsJson);
return props[prop.toLowerCase()] || '';
} catch (e) {}
}
return process.env[`CONNECTION_${connName}_${prop}`] || '';
}host.docker.internal:<port>imagePullPolicyRadius.Compute/containersAlwayskind load/healthz/readyzrad initialize
rad workspace create kubernetes default --group default --environment default
rad environment create myenv --namespace my-namespace # if needed
rad environment switch myenv# Download YAML from radius-resource-types, then register
rad resource-type create Radius.Data/postgreSqlDatabases --from-file postgreSqlDatabases.yaml
rad resource-type show Radius.Data/postgreSqlDatabases # verify
# Repeat for other repo-backed types such as:
# Radius.Data/mySqlDatabases
# Radius.Storage/blobStorages
# Radius.Security/secrets
# Radius.Compute/persistentVolumes
# Radius.Compute/routes
# Radius.AI/agentsrad bicep publish-extension --from-file postgreSqlDatabases.yaml --target radius-data.tgz
# Then add the matching extension key in bicepconfig.json, for example:
# "radiusData": "radius-data.tgz"
# "radiusStorage": "radius-storage.tgz"
# "radiusSecurity": "radius-security.tgz"
# "radiusAi": "radius-ai.tgz"---Critical: Recipes registered from local file paths () will NOT work. The Radius control plane runs inside Kubernetes and cannot access the host filesystem. Always publish to an OCI registry./tmp/recipe.bicep
# Publish to OCI registry
rad bicep publish --file kubernetes-postgresql.bicep \
--target br:myregistry.azurecr.io/recipes/postgresql-kubernetes:latest
# For local/insecure registries, add --plain-http
rad bicep publish --file kubernetes-postgresql.bicep \
--target br:localhost:5001/recipes/postgresql-kubernetes:latest --plain-http
# Register (use host.docker.internal for in-cluster access)
rad recipe register postgresql \
--resource-type Radius.Data/postgreSqlDatabases \
--template-kind bicep \
--template-path "host.docker.internal:5001/recipes/postgresql-kubernetes:latest" \
--plain-http --environment myenv| Constitution Says | Recipe Platform | Recipe IaC | Example |
|---|---|---|---|
| Azure + Terraform | | | |
| Azure + Bicep | | | |
| AWS + Terraform | | | |
| Kubernetes (local) | | | |
docker run -d -p 5001:5000 --name radius-registry registry:2
curl http://localhost:5001/v2/_catalog # verifylocalhosthost.docker.internalNODENAME=$(kubectl get nodes -o jsonpath='{.items[0].metadata.name}')
docker exec $NODENAME mkdir -p /etc/containerd/certs.d/host.docker.internal:5001
docker exec $NODENAME bash -c 'cat > /etc/containerd/certs.d/host.docker.internal:5001/hosts.toml << EOF
[host."http://host.docker.internal:5001"]
capabilities = ["pull", "resolve"]
skip_verify = true
EOF'
docker exec $NODENAME bash -c \
'sed -i "s|config_path = \"\"|config_path = \"/etc/containerd/certs.d\"|" /etc/containerd/config.toml'
docker exec $NODENAME systemctl restart containerddocker build -t myapp-backend:latest ./backend
docker tag myapp-backend:latest localhost:5001/myapp-backend:latest
docker push localhost:5001/myapp-backend:latestapp.bicephost.docker.internal:5001/myapp-backend:latestrad environment list
rad environment show myenv
rad recipe list --environment myenv
rad recipe show postgresql --resource-type Radius.Data/postgreSqlDatabases --environment myenv
rad resource-type list
rad resource-type show Radius.Data/postgreSqlDatabases
rad workspace shownamespace: Radius.Data
types:
postgreSqlDatabases:
description: |
A portable PostgreSQL database resource.
apiVersions:
'2025-08-01-preview':
schema:
type: object
properties:
environment:
type: string
description: "(Required) The Radius Environment ID."
application:
type: string
description: "(Optional) The Radius Application ID."
size:
type: string
enum: ['S', 'M', 'L']
description: "(Optional) The size of the database."
host:
type: string
description: The hostname.
readOnly: true
port:
type: string
description: The port.
readOnly: true
database:
type: string
description: The database name.
readOnly: true
username:
type: string
description: The username.
readOnly: true
password:
type: string
description: The password.
readOnly: true
required: [environment]environmentreadOnly: true<resourceType>/
├── README.md
├── <resourceType>.yaml
└── recipes/
├── kubernetes/bicep/kubernetes-<type>.bicep
├── azure-<service>/bicep/azure-<service>.bicep
└── aws-<service>/terraform/main.tfcontext.resource.id // Full resource ID
context.resource.name // Resource name
context.resource.type // e.g., "Radius.Data/postgreSqlDatabases"
context.resource.properties // Developer-set properties from app.bicep
context.runtime.kubernetes.namespace // Target namespaceImportant: Use(notcontext.resource.properties.*).context.properties.*
param context object
var size = contains(context.resource.properties, 'size') ? context.resource.properties.size : 'S'
var name = context.resource.name
var namespace = context.runtime.kubernetes.namespace
// ... deploy k8s resources ...
output result object = {
properties: {
host: '${name}-svc.${namespace}.svc.cluster.local'
port: '5432'
database: name
username: 'admin'
password: 'generated-password'
}
}variable "context" {
type = any
}
locals {
size = try(var.context.resource.properties.size, "S")
name = var.context.resource.name
namespace = var.context.runtime.kubernetes.namespace
}
output "result" {
value = {
properties = {
host = "${local.name}-svc.${local.namespace}.svc.cluster.local"
port = "5432"
database = local.name
username = "admin"
password = "generated-password"
}
}
}# 1. Publish recipe to OCI registry
rad bicep publish --file kubernetes-postgresql.bicep \
--target br:myregistry.azurecr.io/recipes/postgresql-kubernetes:latest
# 2. Register resource type
rad resource-type create Radius.Data/postgreSqlDatabases --from-file manifest.yaml
# 3. Register recipe
rad recipe register postgresql \
--resource-type Radius.Data/postgreSqlDatabases \
--template-kind bicep \
--template-path "myregistry.azurecr.io/recipes/postgresql-kubernetes:latest"
# 4. Generate Bicep extension
rad bicep publish-extension --from-file manifest.yaml --target radius-data.tgz
# 5. Test
rad run app.bicep| Problem | Cause | Fix |
|---|---|---|
| Missing | Create it with the Radius extension registry URL |
| Recipe registered from local file path | Publish to OCI registry, re-register |
| | Use |
| containerd defaults to HTTPS | Configure |
| Recipe expects property not set in app.bicep | Add the property or add a safe default in recipe |
| No recipe registered for resource type | |
| Image not accessible from cluster | Push to registry; |
| Using | Parse |
Bicep validation errors on | No Bicep extension generated | |
| Wrong property name for container type | |
| Topic | Reference | Use for |
|---|---|---|
| Bicep Patterns | references/bicep-patterns.md | Multi-container apps, gateways, parameterization |
| App Definition Flow | references/app-definition-flow.md | Scaffolding |
| Connection Conventions | references/connection-conventions.md | Env var formats, JSON parsing, portable code |
| Resource Type Catalog | references/resource-type-catalog.md | Available types, schemas, properties |
| Local Development | references/local-development.md | kind, local registry, containerd, Dockerfiles |
| Resource Type YAML | references/resource-type-yaml.md | YAML schema definition format |
| Recipe Authoring | references/recipe-authoring.md | Bicep/Terraform recipes, context object |
| Environment Config | references/environment-config.md | Workspaces, environments, namespaces |
| Cloud Providers | references/cloud-providers.md | Azure, AWS credentials for Radius |
| Recipe Structure | references/recipe-structure.md | Directory layout in radius-resource-types |
| Contribution Guide | references/contribution-guide.md | Contributing to radius-resource-types |
Radius.*environment_PROPERTIESsizebicepconfig.jsonapp.bicepexistingenv.bicepshared-resources.bicepexistingapp.bicepenableObservabilityhost.docker.internallocalhost--plain-httpcontainersRadius.ComputecontainerApplications.Corerad run