If you are using GitHub Copilot, there is an exciting feature you should try: GitHub Copilot custom instructions. With custom instructions, GitHub Copilot can better align with your coding style and workflow, making code generation even faster and more seamless.
In this blog, you will learn about custom instructions and how to use them with real-world examples in Azure Bicep.
What are custom instructions?
A custom instruction is an option for GitHub Copilot used for code generation. The instructions are added to every request when you have a chat with GitHub Copilot. You can leverage custom instructions to adhere to a specific coding style or to add extra guidance, like including documentation, without needing to provide it each time.
The setting github.copilot.chat.codeGeneration.useInstructionFiles is added to Visual Studio Code (v1.98 or higher). This is a boolean value and it instructs GitHub Copilot to look for the copilot-instructions.md in the .github folder.

Another setting is the github.copilot.chat.codeGeneration.instructions. Via this setting you can configure what GitHub Copilot needs to look at. This can either be natural language (text) or a custom file within your workspace:

Be aware what you are supplying, because the text or file has impact on your prompt. So be straight to the point and try to give (code snippet) examples or else it might degrade in quality (and performance)!
Instruction examples
When you have been writing code for a long time, you may have developed certain style habits. I have my own style habits with Azure Bicep, but the issue is that GitHub Copilot does not automatically know what these are. Some of my style habits include:
- Using the hungarian notation
- When using the
existingkeyword I tend to postfix the symbolic name withRef. - Adding a specific format to parameter descriptions such as starting with
Required.when a parameter is required orOptional.when a parameter is optional/nullable.
These are perfect examples to give as custom instructions. Simply add this to the copilot-instructions.md file under the .github folder. The markdown file will look something like this:
| Always use the hungarian notation prefix for the following items: | |
| - Parameters: Prefix with par. For example, parLocation. | |
| - Variables: Prefix with var. For example, varStorageAccountName. | |
| - Resources: Prefix with res. For example, resStorageAccount. | |
| - Modules: Prefix with mod. For example, modStorageAccount. | |
| - Outputs: Prefix with out. For example, outStorageAccountName. | |
| - User-Defined Functions: Prefix with func. For example, funcMyFunctionHere. | |
| - User-Defined Types: Prefix with type. For example, typeMyTypeHere. | |
| When using the existing keyword to refer to resources, append `Ref` to the symbolic name of each resource. For instance, if referencing an existing storage account, use the format `resExistingStorageAccountRef`. | |
| If a parameter name includes βpassword,β βadmin,β or βkey,β apply the @secure decorator to ensure secure handling. For example, use `@secure` with parameters like adminPassword or apiKey. | |
| Always add a description decorator `@description` on parameters and outputs to describe the purpose. If the parameter is required, start the description with `Required.` and when the parameter is optional or nullable start with `Optional.`. | |
| Begin module names with the format deploy-resource-type-${resource-type-name}. For example, in a Key Vault deployment: | |
| ```bicep | |
| @description('Required. The name of the Key Vault.') | |
| param parKeyVaultName string | |
| module modKeyVault 'br/public:avm/res/key-vault/vault:0.9.0' = { | |
| name: 'deploy-key-vault-${parKeyVaultName}' | |
| params: { | |
| name: parKeyVaultName | |
| location: parLocation | |
| } | |
| } | |
| ``` |
This is just a small example of what you can do with copilot-instructions.md. The instructions arenβt limited to Azure Bicep; you can also set coding conventions for PowerShell, such as specifying the outline for a PowerShell function. For best results, try to be detailed and provide examples.
Custom instructions in action
I want to highlight some prompts that can help you take your code suggestions to the next level, ensuring they are precise, context-aware, and aligned with your standard. Each prompt will use the copilot instructions file:

Create new resources
The goal of this prompt is to create resources based on the conventions described in the instructions file.
Prompt
Create an Azure Bicep template that deploys an Azure Key Vault, an existing subnet reference with parameterised virtual network and a private endpoint that is coupled with the Azure Key Vault and placed in the existing subnet.
Input
None (from scratch)
Output

Update parameters in bulk
The goal of this prompt is to update parameters to adhere to the code conventions. Expected changes include adding the par prefix, formatting descriptions in a specific way, and adding descriptions where they are missing.
Prompt
Update the parameters so these follow the code convention.
Input
| @description('The name of the Key Vault.') | |
| param keyVaultName string | |
| @description('The location for the resources.') | |
| param location string | |
| @description('The name of the virtual network.') | |
| param virtualNetworkName string | |
| param virtualNetworkAddressPrefix string | |
| param subnetName string |
Output

Conversion to an Azure Verified Module
Converting existing Bicep resource definitions to Azure Verified Modules (AVM) can be challenging. Since GitHub Copilot does not recognise the AVM reference, it requires additional instructions to understand, such as the path to the AVM container registry and default input parameters like name and location.
Even with clear instructions, this task is not straightforward for GitHub Copilot because the properties in resource definitions can differ from the parameters expected by Azure Verified Modules. The output will show how Copilot handles these differences.
The instructions below are not perfect and may require optimisation due to their length, but they work for now. To familiarise GitHub Copilot with AVM, the following instructions have been added to the copilot-instructions.md file:
| Azure Verified Modules always have the name and location as required parameters. Always pass the name and location as parameters to the module: | |
| ```bicep | |
| module modSymbolicName 'br/public:avm/res/_type_/_resource_:_version_' = { | |
| name: 'storageAccount' | |
| params: { | |
| name: parName | |
| location: parLocation | |
| } | |
| } | |
| ``` | |
| Select one of the Azure Verified Modules listed below and reference it as a template to build the module in the Bicep file. | |
| Azure Active Directory: br/public:avm/res/aad:_version_ | |
| Alerts Management: br/public:avm/res/alerts-management:_version_ | |
| Analysis Services: br/public:avm/res/analysis-services:_version_ | |
| API Management: br/public:avm/res/api-management:_version_ | |
| App Service: br/public:avm/res/app:_version_ | |
| ... | |
| ... |
The instructions above are a subset of the full list of Azure Verified Modules. To see the complete list, check out my GitHub Gist.
Prompt
Convert the resource definition to use Azure Verified Modules. While converting ensure that the company best practices are used. Also, try to map the properties onto the verified module.
Input
| resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { | |
| name: 'my-azure-key-vault' | |
| location: 'westeurope' | |
| properties: { | |
| tenantId: tenant().tenantId | |
| sku: { | |
| name: 'standard' | |
| family: 'A' | |
| } | |
| } | |
| } |
Output

Feedback
The goal of this prompt is to get feedback on the written Azure Bicep template. This can be useful for code reviews or when refactoring existing templates to check if they adhere to your current code standards.

Conclusion
GitHub Copilot is a powerful AI pair programmer that becomes even more effective with custom instructions. These instructions allow you to guide GitHub Copilot on coding conventions and other preferences with each request. To achieve the most optimal results iterative adjustments must be done to tailor the instructions to your needs. I would advise to start with simple instructions and gradually expand these. Additionally, this blog post has a focus on Azure Bicep but custom instructions can be used for many other languages such as PowerShell or C#.