diff --git a/.github/config/en-custom.txt b/.github/config/en-custom.txt
index 78547bdcd..159c0cbac 100644
--- a/.github/config/en-custom.txt
+++ b/.github/config/en-custom.txt
@@ -1301,3 +1301,5 @@ DeploymentTemplate
gitops
auditable
bicepparam
+cleartext
+MyCompany
\ No newline at end of file
diff --git a/docs/content/tutorials/tutorial-resource-type/bicepconfig.json b/docs/content/tutorials/tutorial-resource-type/bicepconfig.json
new file mode 100644
index 000000000..8a5da4006
--- /dev/null
+++ b/docs/content/tutorials/tutorial-resource-type/bicepconfig.json
@@ -0,0 +1,11 @@
+// The bicepconfig.json file is needed so the bicep files for this tutorial can be compiled with the correct setup
+{
+ "experimentalFeaturesEnabled": {
+ "extensibility": true
+ },
+ "extensions": {
+ "radius": "br:biceptypes.azurecr.io/radius:latest",
+ "aws": "br:biceptypes.azurecr.io/aws:latest",
+ "mycompany": "./mycompany.tgz"
+ }
+}
\ No newline at end of file
diff --git a/docs/content/tutorials/tutorial-resource-type/index.md b/docs/content/tutorials/tutorial-resource-type/index.md
new file mode 100644
index 000000000..8f0926d6f
--- /dev/null
+++ b/docs/content/tutorials/tutorial-resource-type/index.md
@@ -0,0 +1,231 @@
+---
+type: docs
+title: "Tutorial: Create a Resource Type in Radius"
+linkTitle: "Create resource type"
+description: "Learn how to define and deploy a resource type in your Radius application"
+weight: 200
+categories: ["resource-types"]
+---
+
+## Overview
+
+Radius includes several built-in resource types which developers can use to build applications. These include core resource types such as containers, gateways, and secrets. You can also create your own resource types. This tutorial guides you through creating a PostgreSQL resource and deploying the sample Todo List application with PostgreSQL.
+
+{{< image src="todolist.png" alt="Diagram of the Todo List with PostgreSQL" width=600px >}}
+
+## Prerequisites
+
+- [A Kubernetes cluster]({{< ref "/guides/operations/kubernetes/overview" >}}) to host Radius and the Todo List application. Make sure to follow the instructions under the [Supported Kubernetes clusters]({{< ref "/guides/operations/kubernetes/overview#supported-kubernetes-clusters" >}}).
+- [rad CLI]({{< ref "installation#step-1-install-the-rad-cli" >}})
+- Store your Recipe at a location.
+ - If you are using Terraform, Radius supports pulling Terraform modules from the following [module sources](https://developer.hashicorp.com/terraform/language/modules/sources): A generic Git repository including GitHub and Bitbucket and Terraform Registry
+ - If you are using Bicep, you must store your Recipe at an [OCI compliant container registry](https://oras.land/docs/compatible_oci_registries/). Make sure the container registry is set up with appropriate permissions to publish and pull Recipes.
+- The [Bicep extension]({{< ref "installation#step-2-install-the-vs-code-extension" >}}) for VS Code is recommended for Bicep language support
+- [Node.js](https://nodejs.org/en/download) is required to generate the Bicep extension to deploy the new resource type.
+
+## Step 1: Install Radius and initialize a new environment
+
+1. Begin in a new directory for your application:
+
+ ```bash
+ mkdir todolist
+ cd todolist
+ ```
+
+1. Initialize a new Radius environment:
+
+ *Select 'No' when prompted to setup application in the current directory?*
+
+ ```bash
+ rad init
+ ```
+
+## Step 2: Create a PostgreSQL resource type in Radius
+
+To create a PostgreSQL resource type in Radius, first create the resource type definition then add the resource type to Radius.
+
+1. Create a new file called `postgreSQL.yaml` and add the following:
+
+ {{% rad file="snippets/postgreSQL.yaml" lang=YAML embed=true %}}
+
+ The PostgreSQL resource type definition includes:
+
+ - `name`: The namespace of the resource type used to group resource types; must be in the form PrimaryName.SecondaryName
+ - `types`: The resource type name
+ - `apiVersions`: The version of the schema defined below; currently must be `2023-10-01-preview`
+ - `schema`: The schema defines the properties of the resource type.
+ - `environment`: The Radius environment in which the resource type is deployed; this property is set by Radius when the resource is deployed
+ - `application`: The application to which the resource belongs to
+ - `status`: This is a read-only property that is set by the Recipe that includes connection information to the resource type.
+ - `capabilities`: This specifies features of the resource type. The only available option is `SupportsRecipes` which indicates that the resource type can be deployed via a Recipe.
+
+
+1. Create the resource type using the [rad resource-type]({{< ref rad_resource-type_create >}}) command:
+
+ ```bash
+ rad resource-type create postgreSQL -f postgreSQL.yaml
+ ```
+
+## Step 3: Register a Recipe for the PostgreSQL resource type
+
+[Recipes]({{< ref "/guides/recipes/overview" >}}) define how resource types are deployed. To deploy the PostgreSQL resource type, you must create a Bicep Template or a Terraform module and publish it to a location. Then register the template or module as a Recipe in the Radius environment.
+
+{{< tabs Terraform Bicep >}}{{% codetab %}}
+
+1. Radius supports pulling Terraform modules from a generic [Git repository](https://developer.hashicorp.com/terraform/language/modules/sources#generic-git-repository), including GitHub. Create a new directory in your Git repository for the PostgreSQL Terraform module and navigate to it:
+
+ Create a new file called `main.tf` and add the following:
+
+ {{% rad file="snippets/recipes/terraform/main.tf" embed=true %}}
+
+ Learn more about Authoring Terraform Modules as Recipes in this [how-to-guide]({{< ref "/guides/recipes/howto-author-recipes" >}}). If you want to pull Terraform modules from a private registry, follow the how-to-guide on [pulling Terraform modules from a private registry](https://docs.radapp.io/guides/recipes/terraform/howto-private-registry/)
+
+1. Register the Terraform module as the `default` Recipe in the `default` environment (the default environment was created when `rad init` was run)
+
+ ```bash
+ rad recipe register default --environment default --resource-type MyCompany.Resources/postgreSQL --template-kind terraform --template-path git::
+ ```
+ For example, if you have the terraform module in your git repository named `terraform-recipes/kubernetes/postgres`, the command would look like this:
+
+ ```bash
+ rad recipe register default --environment default --resource-type MyCompany.Resources/postgreSQL --template-kind terraform --template-path https://github.com//terraform-recipes.git//kubernetes/postgres
+ ```
+
+1. Verify the Recipe is registered to the `default` environment
+
+ ```bash
+ rad recipe list
+ ```
+ You should see the Recipe for the PostgreSQL resource type listed in the output (along with several Bicep recipes that were installed by the rad init command).
+
+ ```bash
+ RECIPE TYPE TEMPLATE KIND TEMPLATE VERSION TEMPLATE
+ default MyCompany.Resources/postgreSQL terraform git::
+ ...
+ ```
+{{% /codetab %}}
+{{% codetab %}}
+1. Create a new file called `postgreSQL.bicep` and add the following:
+
+ {{% rad file="snippets/recipes/bicep/postgreSQL.bicep" embed=true %}}
+
+1. Make sure your preferred OCI-compliant container is set up with appropriate permissions to publish and pull Recipes. For example, if you are using GitHub container registry, follow the instructions [here](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry). The easiest option to authenticate is to generate a Personal Access token (PAT) with read, write and delete access to the package. Follow this [how-to-guide]({{< ref "/guides/recipes/howto-private-bicep-registry" >}}) if you want to publish to a private registry.
+
+1. Publish the Recipe to the container registry using the below command. Make sure to replace `host` and `repository` with your container registry.
+
+ ```bash
+ rad bicep publish --file postgreSQL.bicep --target br://postgresql:latest
+ ```
+1. Register the Bicep template as the `default` Recipe in the `default` environment (the default environment was created when `rad init` was run)
+
+ ```bash
+ rad recipe register default --environment default --resource-type MyCompany.Resources/postgreSQL --template-kind bicep --template-path //postgresql:latest
+ ```
+1. Verify the Recipe is registered to the `default` environment
+
+ ```bash
+ rad recipe list
+ ```
+ You should see the Recipe for the PostgreSQL resource type listed in the output.
+
+ ```bash
+ RECIPE TYPE TEMPLATE KIND TEMPLATE VERSION TEMPLATE
+ default MyCompany.Resources/postgreSQL bicep //postgresql:latest
+ ...
+ ```
+{{% /codetab %}}
+{{< /tabs >}}
+
+## Step 4: Generate a Bicep extension
+
+{{% alert title="Info" color="info" %}}
+This step is required even if you use Terraform Recipes to deploy the PostgreSQL resource type as part of the application.
+{{% /alert %}}
+
+For the rad CLI and VS Code to recognize the PostgreSQL resource type, a [Bicep extension](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-extension) must be generated and added to the [`bicepconfig.json`]({{< ref "/guides/tooling/bicepconfig/overview" >}}) file.
+
+1. Generate the Bicep extension using the [rad bicep publish-extension]({{< ref rad_bicep_publish-extension >}}) command:
+
+ ```bash
+ rad bicep publish-extension -f postgreSQL.yaml --target ./mycompany.tgz
+ ```
+ The Bicep extension `mycompany` is generated and saved to the `mycompany.tgz` file.
+
+1. Open the `bicepconfig.json` file and replace it with the below config.
+
+ ```bash
+ {
+ "experimentalFeaturesEnabled": {
+ "extensibility": true
+ },
+ "extensions": {
+ "radius": "br:biceptypes.azurecr.io/radius:latest",
+ "aws": "br:biceptypes.azurecr.io/aws:latest",
+ "mycompany": "./mycompany.tgz"
+ }
+ }
+ ```
+
+## Step 5: Author the Todo List application with PostgreSQL
+
+1. Create `app.bicep` and add the Todo List application.
+
+ ```bicep
+ extension radius
+ ```
+ {{% rad file="snippets/app.bicep" embed=true marker="//APP" %}}
+
+1. Add the `mycompany` extension and the PostgreSQL resource type
+
+ ```bicep
+ extension mycompany
+ ```
+ {{% rad file="snippets/app.bicep" embed=true marker="//POSTGRESQL" %}}
+
+1. Add the `demo` container definition along with the connection to the PostgreSQL resource type as environment variables.
+
+ {{% rad file="snippets/app.bicep" embed=true marker="//CONTAINER" %}}
+
+ {{% alert title="Caution" color="warning" %}}
+ In this example the POSTGRESQL_PASSWORD is stored as a cleartext property for demo purposes. In production environments, always use secrets to store and reference sensitive information like passwords.
+ {{% /alert %}}
+
+1. Your final `app.bicep` file should look like this:
+
+ {{% rad file="snippets/app.bicep" embed=true %}}
+
+## Step 5: Run the application
+
+Run the application using `rad run`. The `rad run` command sets up port forwarding to the application. .
+
+```sh
+rad run app.bicep --application todolist
+```
+Visit the application at [http://localhost:3000](http://localhost:3000).You should see the Radius Connections section with new environment variables added. The `demo` container now has connection information for PostgreSQL (`CONNECTION_POSTGRESQL_HOST`, `CONNECTION_POSTGRESQL_PORT`, etc.)
+
+{{< image src=todolist_postgresql.png" alt="Todo List with PostgreSQL connection" width=800px >}}
+
+## Step 6: Clean up
+
+To clean up the resources created in this tutorial, run the following commands
+
+1. Delete the application and all resources created by the application
+
+ ```bash
+ rad app delete --application todolist
+ ```
+2. Delete the environment
+
+ ```bash
+ rad env delete --environment default
+ ```
+3. Delete the PostgreSQL resource type
+
+ ```bash
+ rad resource-type delete MyCompany.Resources/postgreSQL
+ ```
+4. Uninstall Radius
+
+ ```bash
+ rad uninstall kubernetes
+ ```
diff --git a/docs/content/tutorials/tutorial-resource-type/mycompany.tgz b/docs/content/tutorials/tutorial-resource-type/mycompany.tgz
new file mode 100644
index 000000000..0e4c2040d
Binary files /dev/null and b/docs/content/tutorials/tutorial-resource-type/mycompany.tgz differ
diff --git a/docs/content/tutorials/tutorial-resource-type/snippets/app.bicep b/docs/content/tutorials/tutorial-resource-type/snippets/app.bicep
new file mode 100644
index 000000000..2284d935f
--- /dev/null
+++ b/docs/content/tutorials/tutorial-resource-type/snippets/app.bicep
@@ -0,0 +1,63 @@
+// Import the set of Radius resources (Applications.*) into Bicep
+extension radius
+// Import the set of MyCompany resources (MyCompany.*) into Bicep
+extension mycompany
+
+//APP
+resource todolist 'Applications.Core/applications@2023-10-01-preview' = {
+ name: 'todolist'
+ properties: {
+ environment: environment
+ }
+}
+//APP
+
+//POSTGRESQL
+param environment string
+resource postgresql 'MyCompany.Resources/postgreSQL@2023-10-01-preview' = {
+ name: 'postgresql'
+ location: 'global'
+ properties: {
+ application: todolist.id
+ environment: environment
+ }
+}
+//POSTGRESQL
+
+//CONTAINER
+resource demo 'Applications.Core/containers@2023-10-01-preview' = {
+ name: 'demo'
+ properties: {
+ application: todolist.id
+ container: {
+ image: 'ghcr.io/radius-project/samples/demo:latest'
+ ports: {
+ web: {
+ containerPort: 3000
+ }
+ }
+ //CONNECTION
+ env: {
+ CONNECTION_POSTGRES_HOST: {
+ value: postgresql.properties.status.binding.host
+ }
+ CONNECTION_POSTGRES_PORT: {
+ value: string(postgresql.properties.status.binding.port)
+ }
+ CONNECTION_POSTGRES_USERNAME: {
+ value: postgresql.properties.status.binding.username
+ }
+ CONNECTION_POSTGRES_DATABASE: {
+ value: postgresql.properties.status.binding.database
+ }
+ //This is stored and passed as cleartext for demo purposes. In production, use a secret store.
+ CONNECTION_POSTGRES_PASSWORD: {
+ value: postgresql.properties.status.binding.password
+ }
+ }
+ }
+ }
+}
+//CONTAINER
+
+
diff --git a/docs/content/tutorials/tutorial-resource-type/snippets/postgreSQL.yaml b/docs/content/tutorials/tutorial-resource-type/snippets/postgreSQL.yaml
new file mode 100644
index 000000000..5c854481c
--- /dev/null
+++ b/docs/content/tutorials/tutorial-resource-type/snippets/postgreSQL.yaml
@@ -0,0 +1,34 @@
+name: MyCompany.Resources
+types:
+ postgreSQL:
+ apiVersions:
+ '2023-10-01-preview':
+ schema:
+ type: object
+ properties:
+ environment:
+ type: string
+ application:
+ type: string
+ status:
+ type: object
+ properties:
+ binding:
+ type: object
+ properties:
+ database:
+ type: string
+ description: The name of the database.
+ host:
+ type: string
+ description: The host name of the database.
+ port:
+ type: string
+ description: The port number of the database.
+ username:
+ type: string
+ description: The username for the database.
+ password:
+ type: string
+ description: The password for the database.
+ capabilities: ["SupportsRecipes"]
\ No newline at end of file
diff --git a/docs/content/tutorials/tutorial-resource-type/snippets/recipes/bicep/postgreSQL.bicep b/docs/content/tutorials/tutorial-resource-type/snippets/recipes/bicep/postgreSQL.bicep
new file mode 100644
index 000000000..7c35b0d3b
--- /dev/null
+++ b/docs/content/tutorials/tutorial-resource-type/snippets/recipes/bicep/postgreSQL.bicep
@@ -0,0 +1,129 @@
+@description('Information about what resource is calling this Recipe. Generated by Radius.')
+param context object
+
+@description('Name of the PostgreSQL database. Defaults to the name of the Radius resource.')
+param database string = context.resource.name
+
+@description('PostgreSQL username')
+param user string = 'postgres'
+
+@description('PostgreSQL password')
+@secure()
+#disable-next-line secure-parameter-default
+param password string = uniqueString(context.resource.id)
+
+@description('Tag to pull for the postgres container image.')
+param tag string = '16-alpine'
+
+@description('Memory request for the postgres deployment.')
+var memoryRequest = '512Mi'
+
+@description('Memory limit for the postgres deployment')
+var memoryLimit = '1024Mi'
+
+extension kubernetes with {
+ kubeConfig: ''
+ namespace: context.runtime.kubernetes.namespace
+} as kubernetes
+
+var uniqueName = 'postgres-${uniqueString(context.resource.id)}'
+var port = 5432
+
+// Based on https://hub.docker.com/_/postgres/
+resource postgresql 'apps/Deployment@v1' = {
+ metadata: {
+ name: uniqueName
+ }
+ spec: {
+ selector: {
+ matchLabels: {
+ app: 'postgresql'
+ resource: context.resource.name
+ }
+ }
+ template: {
+ metadata: {
+ labels: {
+ app: 'postgresql'
+ 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 postgresql instance.
+ name: 'postgres'
+ image: 'postgres:${tag}'
+ ports: [
+ {
+ containerPort: port
+ }
+ ]
+ resources: {
+ requests: {
+ memory: memoryRequest
+ }
+ limits: {
+ memory: memoryLimit
+ }
+ }
+ env: [
+ {
+ name: 'POSTGRES_USER'
+ value: user
+ }
+ {
+ name: 'POSTGRES_PASSWORD'
+ value: password
+ }
+ {
+ name: 'POSTGRES_DB'
+ value: database
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
+
+resource svc 'core/Service@v1' = {
+ metadata: {
+ name: uniqueName
+ labels: {
+ name: uniqueName
+ }
+ }
+ spec: {
+ type: 'ClusterIP'
+ selector: {
+ app: 'postgresql'
+ resource: context.resource.name
+ }
+ ports: [
+ {
+ port: port
+ }
+ ]
+ }
+}
+
+output result object = {
+ resources: [
+ '/planes/kubernetes/local/namespaces/${svc.metadata.namespace}/providers/core/Service/${svc.metadata.name}'
+ '/planes/kubernetes/local/namespaces/${postgresql.metadata.namespace}/providers/apps/Deployment/${postgresql.metadata.name}'
+ ]
+ values: {
+ host: '${svc.metadata.name}.${svc.metadata.namespace}.svc.cluster.local'
+ port: port
+ database: database
+ username: user
+ }
+ secrets: {
+ #disable-next-line secure-parameter-default
+ password: password
+ }
+}
diff --git a/docs/content/tutorials/tutorial-resource-type/snippets/recipes/terraform/main.tf b/docs/content/tutorials/tutorial-resource-type/snippets/recipes/terraform/main.tf
new file mode 100644
index 000000000..4e68e1506
--- /dev/null
+++ b/docs/content/tutorials/tutorial-resource-type/snippets/recipes/terraform/main.tf
@@ -0,0 +1,98 @@
+terraform {
+ required_providers {
+ kubernetes = {
+ source = "hashicorp/kubernetes"
+ version = ">= 2.0"
+ }
+ }
+}
+
+variable "context" {
+ description = "This variable contains Radius recipe context."
+ type = any
+}
+
+locals {
+ uniqueName = var.context.resource.name
+ port = 5432
+ namespace = var.context.runtime.kubernetes.namespace
+}
+
+resource "random_password" "password" {
+ length = 16
+}
+
+resource "kubernetes_deployment" "postgresql" {
+ metadata {
+ name = local.uniqueName
+ namespace = local.namespace
+ }
+
+ spec {
+ selector {
+ match_labels = {
+ app = "postgres"
+ }
+ }
+
+ template {
+ metadata {
+ labels = {
+ app = "postgres"
+ }
+ }
+
+ spec {
+ container {
+ image = "postgres:16-alpine"
+ name = "postgres"
+ env {
+ name = "POSTGRES_PASSWORD"
+ value = random_password.password.result
+ }
+ env {
+ name = "POSTGRES_USER"
+ value = "postgres"
+ }
+ env {
+ name = "POSTGRES_DB"
+ value = "postgres_db"
+ }
+ port {
+ container_port = local.port
+ }
+ }
+ }
+ }
+ }
+}
+
+resource "kubernetes_service" "postgres" {
+ metadata {
+ name = local.uniqueName
+ namespace = local.namespace
+ }
+
+ spec {
+ selector = {
+ app = "postgres"
+ }
+
+ port {
+ port = local.port
+ target_port = local.port
+ }
+ }
+}
+
+output "result" {
+ value = {
+ values = {
+ host = "${kubernetes_service.postgres.metadata[0].name}.${kubernetes_service.postgres.metadata[0].namespace}.svc.cluster.local"
+ port = local.port
+ database = "postgres_db"
+ username = "postgres"
+ password = random_password.password.result
+ }
+ }
+}
\ No newline at end of file
diff --git a/docs/content/tutorials/tutorial-resource-type/todolist.png b/docs/content/tutorials/tutorial-resource-type/todolist.png
new file mode 100644
index 000000000..0b1c0dfc4
Binary files /dev/null and b/docs/content/tutorials/tutorial-resource-type/todolist.png differ
diff --git a/docs/content/tutorials/tutorial-resource-type/todolist_postgresql.png b/docs/content/tutorials/tutorial-resource-type/todolist_postgresql.png
new file mode 100644
index 000000000..16627209f
Binary files /dev/null and b/docs/content/tutorials/tutorial-resource-type/todolist_postgresql.png differ