
If you are not familiar with the oc command, refer to OpenShift - Getting Started with the oc command.
Let's say you have the following in a YAML file. In this trivial example, a resource named my-project-request-template will be created so that when a new project is created, the new project will have annotation openshift.io/description: proof of concept.
apiVersion: template.openshift.io/v1
kind: Template
metadata:
name: my-project-request-template
objects:
- apiVersion: project.openshift.io/v1
kind: Project
metadata:
annotations:
openshift.io/description: proof of concept
openshift.io/display-name: ${PROJECT_DISPLAYNAME}
openshift.io/requester: ${PROJECT_REQUESTING_USER}
name: ${PROJECT_NAME}
parameters:
- name: PROJECT_NAME
- name: PROJECT_DISPLAYNAME
- name: PROJECT_REQUESTING_USER
Then the oc apply or oc create command with the -f or --filename option can be used to create the template in the openshift-config namespace.
~]$ oc create --filename my-project-request-templat.yml --namespace openshift-config
template.template.openshift.io/my-project-request-templat created
The oc get templates command can be used to show that the template now exists in the openshift-config namespace.
~]$ oc get templates --namespace openshift-config
NAME DESCRIPTION PARAMETERS OBJECTS
my-project-request-template 0 (all set) 1
To make it so that the template is used when new projects are created edit the following resource.
oc edit project.config.openshift.io/cluster
And update the following, where name is an exact match of the name returned by the oc get templates --namespace openshift-config command
spec:
projectRequestTemplate:
name: my-project-request-template
Or in the OpenShift console, at Administration > Cluster Settings > Project > YAML tab.

The pods in the openshift-apiserver namespace should automatically restart. After each pod has restarted, the change should be live.
~]$ oc get pods --namespace openshift-apiserver
NAME READY STATUS RESTARTS AGE
apiserver-59c8df77f6-qpzmx 0/2 Pending 0 41s
apiserver-846d775c67-kjjdx 2/2 Running 0 44d
apiserver-846d775c67-r8n5c 2/2 Terminating 0 44d
apiserver-846d775c67-wj665 2/2 Running 0 44d
Let us the oc new-project to create a new project.
oc new-project my-project
Or in the OpenShift console, at Home > Projects > Create Project.

In this example, the project indeed has annotation openshift.io/description: proof of concept. Nice, it works!
~]$ oc get project jeremy-test --output yaml
apiVersion: project.openshift.io/v1
kind: Project
metadata:
annotations:
openshift.io/description: proof of concept
openshift.io/display-name: my project
openshift.io/requester: john.doe
openshift.io/sa.scc.mcs: s0:c33,c17
openshift.io/sa.scc.supplemental-groups: 1001090000/10000
openshift.io/sa.scc.uid-range: 1001090000/10000
creationTimestamp: "2025-06-11T01:35:52Z"
labels:
kubernetes.io/metadata.name: my-project
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: v1.24
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: v1.24
name: my project
resourceVersion: "546950679"
uid: 1d80a319-c99a-4873-93f0-705fe5f6b438
spec:
finalizers:
- kubernetes
status:
phase: Active
The above example was trivial, where new projects will have annotation openshift.io/description: proof of concept. As a more realistic example, the oc adm create-bootstrap-project-template command can be used to create a YAML file that contains common project template settings.
oc adm create-bootstrap-project-template --output yaml > my-project-template.yml
Be default, the YAML file should contain the following markup.
~]$ cat my-project-template.yml
apiVersion: template.openshift.io/v1
kind: Template
metadata:
creationTimestamp: null
name: project-request
objects:
- apiVersion: project.openshift.io/v1
kind: Project
metadata:
annotations:
openshift.io/description: ${PROJECT_DESCRIPTION}
openshift.io/display-name: ${PROJECT_DISPLAYNAME}
openshift.io/requester: ${PROJECT_REQUESTING_USER}
creationTimestamp: null
name: ${PROJECT_NAME}
spec: {}
status: {}
- apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
creationTimestamp: null
name: admin
namespace: ${PROJECT_NAME}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: ${PROJECT_ADMIN_USER}
parameters:
- name: PROJECT_NAME
- name: PROJECT_DISPLAYNAME
- name: PROJECT_DESCRIPTION
- name: PROJECT_ADMIN_USER
- name: PROJECT_REQUESTING_USER
Let's modify the YAML file. In this example, the options block contains knnd: LimitRange to set the minimum and maxiumum amount of CPU and memory for all of the containers in the project (see Create CPU Memory Limits using a YAML template file).
apiVersion: template.openshift.io/v1
kind: Template
metadata:
creationTimestamp: null
name: my-project-request-template
objects:
- apiVersion: v1
kind: LimitRange
metadata:
name: "${PROJECT_NAME}-resource-limits"
spec:
limits:
- type: Container
default:
cpu: 50m
memory: 1Gi
- apiVersion: project.openshift.io/v1
kind: Project
metadata:
annotations:
openshift.io/description: ${PROJECT_DESCRIPTION}
openshift.io/display-name: ${PROJECT_DISPLAYNAME}
openshift.io/requester: ${PROJECT_REQUESTING_USER}
creationTimestamp: null
name: ${PROJECT_NAME}
spec: {}
status: {}
- apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
creationTimestamp: null
name: admin
namespace: ${PROJECT_NAME}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: ${PROJECT_ADMIN_USER}
parameters:
- name: PROJECT_NAME
- name: PROJECT_DISPLAYNAME
- name: PROJECT_DESCRIPTION
- name: PROJECT_ADMIN_USER
- name: PROJECT_REQUESTING_USER
Then the oc apply or oc create command with the -f or --filename option can be used to create the template in the openshift-config namespace.
~]$ oc create --filename my-project-template.yml --namespace openshift-config
template.template.openshift.io/project-request created
The oc get templates command can be used to show that the template now exists in the openshift-config namespace.
~]$ oc get templates --namespace openshift-config
NAME DESCRIPTION PARAMETERS OBJECTS
my-project-request-template 0 (all set) 1
my-project-template 5 (5 blank) 3
To make it so that the template is used when new projects are created edit the following resource.
oc edit project.config.openshift.io/cluster
And update the following, where name is an exact match of the name returned by the oc get templates --namespace openshift-config command
spec:
projectRequestTemplate:
name: my-project-template
Or in the OpenShift console, at Administration > Cluster Settings > Project > YAML tab.

The pods in the openshift-apiserver namespace should automatically restart. After each pod has restarted, the change should be live.
~]$ oc get pods --namespace openshift-apiserver
NAME READY STATUS RESTARTS AGE
apiserver-59c8df77f6-qpzmx 0/2 Pending 0 41s
apiserver-846d775c67-kjjdx 2/2 Running 0 44d
apiserver-846d775c67-r8n5c 2/2 Terminating 0 44d
apiserver-846d775c67-wj665 2/2 Running 0 44d
Let us the oc new-project to create a new project.
oc new-project my-project
Or in the OpenShift console, at Home > Projects > Create Project.

In this example, since my-project-requests-template contained a spec to create a limits resource named my-project-resource-limits, the oc get limits command can be used to see that now, by default, when a new project is created, the my-project-resource-limits resource will also be created.
~]$ oc get limits --namespace my-project
NAME CREATED AT
my-project-resource-limits 2022-08-06T03:43:59Z
Did you find this article helpful?
If so, consider buying me a coffee over at