Every governance problem in a large estate is cheaper to prevent at creation than to remediate afterwards.
A repository that arrives with an owner, a classification, a CODEOWNERS, a licence and a working pipeline never appears in a drift report. One that arrives empty will appear in every drift report for the next five years.
The short answer
Section titled “The short answer”A template repository is copied when a new repository is created from it. Its files become the new repository’s initial commit.
Templates carry files, not configuration. Branch protection, secrets, environments, webhooks and permissions do not come from a template.
Which means the template is half the answer. The other half is the creation path — the flow that applies settings, collects metadata, assigns ownership and registers the repository.
Central mechanisms cover most of the configuration half. Rulesets, organisation settings and shared workflows apply to repositories that already exist, so the creation path does not need to configure them individually.
The design goal: creating a repository properly should be faster and more useful than creating one improperly.
What belongs in a template
Section titled “What belongs in a template”A README with the sections you want filled in. Placeholders prompt; an empty file does not. What it is, who owns it, how to run it, how to contribute.
A CODEOWNERS — even as a placeholder with an instruction to complete it. Its absence is why pull requests sit unassigned.
A licence, appropriate to the repository’s visibility class.
A .gitignore for the ecosystem, which prevents the build-output problem before it starts. See binary file strategy.
A SECURITY.md stating how to report a vulnerability.
A CONTRIBUTING.md where contributions are expected, including the review-time commitment. See innersource.
Workflow files that call shared workflows, rather than containing pipeline logic. A few lines invoking a centrally-maintained workflow, so improvements reach every repository. See standardised CI/CD.
A pull request template, if your organisation uses one.
Nothing speculative. A template full of files nobody needs teaches people to delete things from templates, which is a habit that eventually deletes something that mattered.
What templates cannot do
Section titled “What templates cannot do”The gap that surprises people, and the reason the creation path matters.
Branch protection and rulesets. Not carried by a template — but largely solved centrally, since rulesets target repositories by property and apply to new ones automatically.
Secrets, variables and environments. Not carried. Organisation-level secrets cover shared cases; repository-specific ones must be set.
Webhooks and app installations. Not carried, though organisation-level configuration covers most.
Teams and permissions. Not carried, and this is the significant one — a new repository has no team grants until somebody adds them.
Custom property values. Not carried by the template, though they can be required at creation.
Topics and description. Not carried.
Which produces the design conclusion: put in the template what must be a file, put in central configuration what can be, and put the rest in the creation path.
Making the template earn its place
Section titled “Making the template earn its place”A template that only imposes obligations will be resented. One that gives something is adopted willingly, and the difference is a design choice.
A working pipeline on the first commit. The strongest single feature. A repository where git push produces a green build, without anybody configuring anything, is a repository people are glad they created from the template.
A working local development setup. A devcontainer configuration, a Makefile, or whatever your ecosystem uses. The first hour of a new project is setup, and eliminating it is felt immediately.
Pre-wired observability. Logging configuration, health check endpoints, the standard metrics. Whatever every service in your organisation needs and every service author writes from scratch.
Sensible dependency versions, current at template-review time.
Documentation that is already half-written. Section headings prompt completion; a blank file does not.
The framing that matters: the template is not a compliance artifact that happens to contain useful files. It is a useful starting point that happens to satisfy compliance. That distinction determines whether people reach for it or route around it, and it costs nothing to design for.
Which is also the argument for reviewing what people delete. Deletions are feedback on what the template imposes without giving anything back.
The creation path
Section titled “The creation path”The flow somebody follows to get a new repository, and the highest-leverage thing a platform team can build.
What it should do:
Ask the questions. Owning team, tier, data classification, purpose. These become custom properties.
Apply the right template, chosen by the repository’s type rather than picked from a list of twelve.
Set the properties, so every targeted policy applies immediately.
Grant the owning team access.
Register it wherever else it needs to exist — the service catalogue, the on-call system, the inventory.
Return something useful. The repository URL, the next steps, and confirmation of what was configured.
And be fast. Ninety seconds, not a ticket.
Restricting creation, and why to avoid it
Section titled “Restricting creation, and why to avoid it”The blunt alternative is an enterprise policy restricting repository creation to organisation owners.
It works in the sense that every repository goes through a person who can collect the metadata.
And it creates a queue. Queues have latency, latency is friction, and friction gets routed around — a repository created in a different organisation, a personal account, or on another platform entirely.
It also makes the platform team a bottleneck for something that should take ninety seconds.
Prefer requiring metadata over restricting creation. GitHub documents an option requiring explicit user-specified values for a custom property, which means a repository cannot be created without one — self-service, with the essential data guaranteed. Verify current behaviour, since repository policies are documented as being in public preview.
Restrict creation only where the population genuinely warrants it — an organisation holding regulated material, for instance, where each new repository is a scope decision.
Building the creation tool
Section titled “Building the creation tool”The engineering, which is smaller than it sounds.
A form and a workflow is enough. An issue form or a simple internal page collecting the answers, and a workflow or script that acts on them. No platform required.
The steps it performs:
1. Validate the inputs (name convention, team exists, tier is valid)2. Create the repository from the chosen template3. Set the custom properties4. Grant the owning team the appropriate permission5. Set the description and topics6. Register in the catalogue / inventory7. Report back the URL and what was configuredAuthenticate as a GitHub App, with narrow permissions: repository creation and administration in the target organisations. Not a personal token. See machine identities.
Make it idempotent where it can be. Re-running after a partial failure should complete rather than duplicate.
Log every creation. What was requested, by whom, what was created. This is both an audit trail and the data for the “created through the governed path” metric.
Handle the failure cases. Name already taken, team does not exist, insufficient permission. Each should produce an actionable message rather than a stack trace.
Start with the minimum. Create, set properties, grant the team. Everything else can be added later, and a tool that does three things well today is worth more than one that does nine things in six months.
The metrics that tell you it works
Section titled “The metrics that tell you it works”Repositories created through the path, as a proportion of all new repositories. The primary metric, and the one that says whether the tool is actually being used.
Time to create. If it exceeds a couple of minutes, adoption will suffer.
Metadata completeness on new repositories. Should be 100% for anything created through the path, which makes any shortfall a direct measure of the bypass rate.
Drift on repositories created since the path existed, compared with those created before. This is the number that demonstrates the value, and the gap is usually dramatic.
Failed creation attempts. Each is either a bug or a validation rule that is too strict.
Templates used, by frequency. A template nobody chooses is a template to retire.
Report the first metric monthly. A creation path used for 40% of new repositories is a partial success with an obvious next question: why do the other 60% not use it?
Keeping templates current
Section titled “Keeping templates current”Templates decay. A template written two years ago reflects two-year-old conventions, and every repository created from it inherits them.
Version them. A template is a repository; treat its contents as code, with review.
Review them quarterly. What is in it, what should be, what nobody uses.
Watch what people delete. If every repository created from the template deletes the same file, that file should not be in the template.
Watch what people add. If every repository adds the same thing, it belongs in the template.
Keep the number small. One per genuine repository type — a service, a library, a documentation site — not one per team. Twelve templates is a menu nobody can choose from, and eleven of them will be stale.
Templates cannot update existing repositories. A change to a template affects repositories created afterwards only. Anything that must reach existing repositories needs a central mechanism or a campaign. This is the strongest argument for keeping pipeline logic in shared workflows rather than in template files.
Templates versus generators
Section titled “Templates versus generators”Two approaches to the same problem, with different trade-offs.
A template repository is copied verbatim. Simple, native to GitHub, and requires no tooling. The copy contains placeholders that somebody must replace.
A generator — a scaffolding tool — produces files from parameters. The service name appears correctly throughout, the package identifier matches, the workflow references the right paths. Nothing to find and replace.
Generators produce better initial repositories. A service repository generated with its name substituted everywhere is immediately correct; a template copy has REPLACE_ME in eleven places, and three of them will survive to production.
Templates are simpler to maintain. They are just files, editable by anybody, with no templating language to learn.
The pragmatic split: use a template for the simple, mostly-static content, and a generator where substitution genuinely matters — service repositories, where the name appears in the package, the workflow, the deployment configuration and the documentation.
A generator can run inside the creation path, which is the natural home for it. The path already has the parameters.
And a generator has the same decay problem. Its output reflects the conventions of whenever it was last updated, so it needs the same review cadence.
Do not build a generator first. Start with a template and a creation path. Add generation when the find-and-replace burden justifies it, which for a documentation repository it never will and for a service repository it quickly does.
The default branch and initial state
Section titled “The default branch and initial state”Small details that are set once per repository and are annoying to change afterwards.
The default branch name is set at creation, and an enterprise policy can enforce it. Changing it later is possible and touches every clone, every CI configuration and every documentation link.
The initial commit’s author. A repository created by automation has an initial commit authored by the automation identity, which is correct and occasionally confusing.
Whether it starts empty or with content. An empty repository has no default branch, which breaks anything assuming one — including some automation. Templates avoid this by producing an initial commit.
Merge strategy settings — whether merge commits, squashing and rebasing are permitted — are organisation-configurable and worth setting deliberately rather than per repository.
Automatic branch deletion on merge should be on, set at the organisation level so every repository inherits it. This addresses the branch accumulation problem before it starts. See repository health.
Feature toggles — issues, projects, wikis, discussions — default on. Deciding which your organisation actually uses, and setting the defaults accordingly, avoids an estate of empty wikis.
Most of these belong in organisation settings rather than in the creation path, because organisation settings apply to repositories created any way at all — including the ones that bypass your tool.
Common mistakes
Section titled “Common mistakes”Expecting templates to carry configuration. They carry files.
No creation path. The template exists and nobody applies it consistently.
A creation path that is slower than not using it. People will not use it.
Restricting creation instead of governing it. A queue that gets bypassed.
Twelve templates. Nobody can choose, and most are stale.
Speculative files in the template. Teaches people to delete things.
Pipeline logic in template files. Cannot be updated centrally afterwards.
Never reviewing templates. They encode conventions from years ago.
Assuming a template change reaches existing repositories. It does not.
Rolling it out
Section titled “Rolling it out”-
Set the organisation defaults first. Default branch name, automatic branch deletion, merge strategies, feature toggles, base Actions permissions. These apply to every repository regardless of how it is created, which makes them the highest-coverage change available.
-
Establish the rulesets that should apply to new repositories, targeted by property. A repository created tomorrow with the right property is governed from its first commit.
-
Build one template, for the most common repository type. Not four.
-
Build the creation path doing the minimum: create, set properties, grant the team.
-
Use it yourself for a month. Every rough edge you tolerate, a user will not.
-
Announce it as a convenience, not a policy. “Creating a repository this way sets everything up for you” lands better than “all repositories must be created this way”.
-
Measure adoption. Track the proportion of new repositories arriving through it.
-
Ask the non-adopters why. The answer is usually a missing capability or a speed problem, and it is the roadmap.
-
Then consider requiring metadata, once the path is the obviously easier route.
Step 1 delivers most of the value and takes an afternoon. Steps 3 and 4 take a week. Everything after that is refinement.
Do not start with step 9. Requiring metadata before there is an easy way to provide it produces resentment and workarounds.
Retrofitting existing repositories
Section titled “Retrofitting existing repositories”The template addresses the future. The existing estate needs a different approach.
Central mechanisms cover most of it. Rulesets, organisation settings and shared workflows apply to repositories that already exist, and they should be the first move — one change, whole estate.
Files are the remainder. A CODEOWNERS, a SECURITY.md, a .gitignore — these must exist in each repository, and getting them there is a campaign. See API automation.
Prioritise by consequence. A missing CODEOWNERS on an active production repository matters; the same on a dormant one does not. Scope the campaign by classification rather than running it across everything.
Do not retrofit the dead tail. Repositories with no activity in a year should be archived, not brought up to standard. Fixing them is work that produces nothing. See repository lifecycle.
Accept partial coverage. A campaign reaching 85% of active repositories, with the remainder documented, is a good outcome. Chasing the last 15% — archived, broken, unowned, unusual — costs more than it returns.
And measure the two populations separately. Compliance among repositories created since the path existed, and compliance among older ones. Conflating them hides the fact that the creation path is working.
Owning the templates
Section titled “Owning the templates”Templates fail the same way shared libraries fail: they become everybody’s dependency and nobody’s responsibility.
Name an owning team. Usually the platform or developer experience function.
Put them under CODEOWNERS. A change to a template affects every repository created afterwards, and it deserves review.
Accept contributions. The teams using the template know what is wrong with it, and a template that only its owners can change will drift from what people need. This is innersource applied to the tooling.
Version the changes visibly. A changelog for the template, so somebody wondering why two repositories differ can see when the template changed.
Announce significant changes. Not because they affect existing repositories — they do not — but because teams creating repositories should know what they will get.
Retire templates deliberately. An unused template should be archived with a note pointing at its replacement, not left to confuse the next person choosing from the list.
And review the set annually as a set, not just individually. The question is whether the categories still match how the organisation builds things, and after two years they frequently do not.
Mental model
Section titled “Mental model”A template is the file half of a new repository. The creation path is the configuration, metadata and registration half, and it is the half that governance depends on. Build the path so that using it is the fastest way to get a working repository, and compliance stops being something anybody has to choose.
What you learned
Section titled “What you learned”- A template’s files become the new repository’s initial commit; configuration is not carried
- Branch protection, secrets, environments, teams and properties all need a mechanism other than the template
- Rulesets and organisation settings cover much of the configuration centrally, including for new repositories
- The creation path should collect metadata, apply the template, set properties, grant team access and register the repository
- Requiring explicit custom property values is preferable to restricting who may create repositories
- Restricting creation produces a queue, and queues get bypassed
- Keep the template set small and review it quarterly, watching what people add and delete
- A template change does not reach existing repositories, which is why pipeline logic belongs in shared workflows
Exercise
Section titled “Exercise”Use an organisation you administer.
-
Create a repository from your current template. List what it arrived with. Predict: did it have branch protection?
-
List what a compliant repository in your organisation needs. Mark each as: template, central configuration, or creation path.
-
Count how many are currently in the creation path. Predict: is there a creation path at all?
-
Time creating a repository properly versus creating one directly. Which is faster?
-
Look at five recently created repositories. How many have an owning team and a tier set?
-
Read your template’s files. Which have not been reviewed in a year?
-
Check three repositories created from the template. What did they delete, and what did they add?
-
Design the creation path you would build, and estimate the work.