{"id":4708,"date":"2025-08-01T21:58:33","date_gmt":"2025-08-01T19:58:33","guid":{"rendered":"https:\/\/gokhan-gokalp.com\/?p=4708"},"modified":"2025-08-01T21:58:33","modified_gmt":"2025-08-01T19:58:33","slug":"devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control","status":"publish","type":"post","link":"https:\/\/gokhan-gokalp.com\/tr\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/","title":{"rendered":"DevEx Series 01: Creating Golden Paths with Backstage, Developer Self-Service Without Losing Control"},"content":{"rendered":"<p>As an architect involved in platform engineering and <em>DevEx<\/em> transformation within a large-scale organization for the past few years, I\u2019ve seen firsthand how developer experience directly shapes not just the speed and quality of software delivery, but also how effectively teams can adopt <strong>governance<\/strong>, <strong>security<\/strong>, and <strong>compliance<\/strong> practices as enablers rather than blockers. I can truly say this was made possible by establishing proven <strong>golden paths<\/strong> and enabling true <strong>developer self-service<\/strong>.<\/p>\n<p data-pm-slice=\"0 0 []\">In this first post, I will try to explain how we can use <em><strong>Backstage<\/strong><\/em> to create these golden paths. Predefined, opinionated software templates that help developers spin up new services quickly and stay compliant without added friction.<\/p>\n<p data-pm-slice=\"0 0 []\">Before diving deeper, it&#8217;s worth clarifying first what we mean by platform engineering and <em>DevEx.<\/em><\/p>\n<h1 data-pm-slice=\"0 0 []\">What Do We Mean by Platform Engineering, DevEx and IDPs?<\/h1>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/road-scaled.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-4734 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/road-scaled.jpg\" alt=\"\" width=\"2560\" height=\"1707\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/road-scaled.jpg 2560w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/road-300x200.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/road-1024x683.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/road-768x512.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/road-1536x1024.jpg 1536w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/road-2048x1365.jpg 2048w\" data-sizes=\"(max-width: 2560px) 100vw, 2560px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 2560px; --smush-placeholder-aspect-ratio: 2560\/1707;\" \/><\/a><\/p>\n<h2><strong>Platform Engineering<\/strong><\/h2>\n<p>I can say, it is the discipline of building and maintaining the internal infrastructure, tooling, and workflows that empower development teams and enable self-service capabilities. It\u2019s like providing a paved road for developers to drive on. It creates kind an abstraction layer between developers and operations that not only shields developers from unnecessary complexity but also ensures that operational, security, and compliance concerns are handled by design.<\/p>\n<h3>Why Did Platform Engineering Emerge?<\/h3>\n<p data-pm-slice=\"0 0 []\">In my experience, as organizations scale their engineering teams and adopt cloud-native architectures, development teams face growing friction. They spend increasing amounts of time setting up infrastructure, understanding <em>CI\/CD<\/em> pipelines, managing permissions, complying with security policies and often reinventing the wheel in slightly different ways.<\/p>\n<p data-pm-slice=\"0 0 []\">While <em>DevOps<\/em> also is meant to bridge the gap between development and operations, in practice it often shifts more operational responsibilities onto developers without providing the right tools or abstractions. Today, with new tools popping up constantly, things have become even more complex. The usual result is cognitive overload, inconsistent practices, and slower delivery.<\/p>\n<p>In contrast, platform engineering brings a <strong>product mindset<\/strong> to internal infrastructure. It focuses on building reusable, self-service platforms that abstract away complexity while enforcing standards.<\/p>\n<p>These platforms are often referred to as <em><strong>Internal Developer Platforms<\/strong><\/em> (<em>IDPs<\/em>), and are designed to give developers everything they need to build, deploy, and operate software efficiently and securely. You can think of an <em>IDP<\/em> as something like <em>ServiceNow<\/em>, but built specifically for developers. Just as <em>ServiceNow<\/em> provides a centralized place for business users to request <em>IT<\/em> services, an <em>IDP<\/em> provides a unified interface where developers can access templates, provision infrastructure, set up <em>CI\/CD<\/em>, or request resources all in a consistent and compliant way.<\/p>\n<p>While it is possible to build your own centralized platform automation control plane, for example, you might use tools like <em>Crossplane<\/em>, <em>Tofu Controller,\u00a0Argo CD<\/em>\u00a0and <em>OPA<\/em> on top of <em>k8s<\/em> to make that happen, of course depending on your <em>IaC<\/em> and <em>GitOps<\/em> strategy, there are also mature tools and reference architectures available that are worth exploring. You can take a look at some of them <em><a href=\"https:\/\/humanitec.com\/reference-architectures\">here<\/a><\/em>.<\/p>\n<h2><strong>Developer Experience (DevEx)<\/strong><\/h2>\n<p data-pm-slice=\"1 1 []\"><em>DevEx<\/em> refers to the overall experience developers have throughout the software development lifecycle. It includes everything from how quickly developers can start a new project to how easily they can locate documentation, access infrastructure and tooling, and troubleshoot problems. It\u2019s about removing friction at every step, giving <strong>clear paths<\/strong>, <strong>fast feedback loops<\/strong>, and <strong>removing unnecessary toil<\/strong>.<\/p>\n<p>Good <em>DevEx<\/em> means developers spend less time on repetitive, low value tasks and more time solving real business problems and driving innovation. It reduces frustration and boosts productivity, all while improving <strong>consistency<\/strong> and <strong>compliance<\/strong> across environments.<\/p>\n<p>When we invest in <em>DevEx<\/em>, we are not just improving developer happiness. We are increasing productivity, quality, and engagement. That in turn, directly impacts an organization\u2019s ability to move faster, respond to market demands, and create more room for innovation.<\/p>\n<p data-pm-slice=\"0 0 []\">In short, while <em>DevEx<\/em> is about the overall experience, <em>IDPs<\/em> and <em>Developer Portals<\/em> (<em>DevEx Portals<\/em>) are how we can bring that experience to life. The platform provides the underlying capabilities, the engine, enabling things like self-service infrastructure provisioning, <em>CI\/CD<\/em> pipelines and policy enforcement in standardized and secure way. The portal is the <em>UI<\/em> for these platform capabilities, a single pane of glass where developers can access everything they need from templates and docs to services, <em>APIs<\/em> and observability tools.<\/p>\n<p>In my experience, platform engineering plays an important role in shaping <em>DevEx<\/em> by providing the paved paths, guardrails and tools developers need to move fast and safely. When done right, it enables teams to ship confidently without sacrificing standards or autonomy.<\/p>\n<p data-pm-slice=\"0 0 []\">Also, one thing I have observed is that when some people talk about improving <em>DevEx<\/em>, the conversation often jumps straight to infrastructure layers, <em>IDPs<\/em>, or complex automation frameworks. While those are undoubtedly powerful and lay the foundation, in my view and based on my experience, they are not always the most <strong>accessible<\/strong> or <strong>practical<\/strong> starting point, especially for teams that aren\u2019t yet ready for full platform engineering efforts.<\/p>\n<p>In my view, I might be also wrong, you can begin your <em>DevEx<\/em> journey by bringing standardization, documentation, and discoverability to your existing software assets. This is where tools like <em>Backstage<\/em> (a <em>DevEx Portal<\/em>) come in.<\/p>\n<p><em>Backstage<\/em> helps teams create <strong>golden paths <\/strong>that are\u00a0well-defined, <strong>reusable<\/strong> templates and documentation that guide developers through consistent ways of building software. It offers a central <em>DevEx Portal<\/em>, or single pane of glass, where developers can find everything they need, from <em>APIs<\/em> and services to documentation and <em>CI\/CD<\/em> status, without jumping between tools. As the organization matures, it also allows seamless integration with broader platform capabilities, including the <em>IDP<\/em>.<\/p>\n<p>So, with that being said, let\u2019s dive into <em>Backstage<\/em> and see how it can help us create golden paths and improve <em>DevEx<\/em> from <strong>day one<\/strong>.<\/p>\n<h2>Backstage: The DevEx Portal<\/h2>\n<p><em>Backstage<\/em> is an open-source <em>DevEx Portal<\/em>\u00a0originally created by <em>Spotify. <\/em>It enables organizations to centralize and standardize how software assets, developer workflows, infrastructure components, and tools are managed. By bringing everything into a single, self-service interface, <em>Backstage<\/em> helps reduce context switching, promote consistency, and improve developer productivity at scale.<\/p>\n<h3>And that really matters<\/h3>\n<p data-pm-slice=\"0 0 []\">Because if you think about the typical developer&#8217;s day, it&#8217;s filled with small but constant interruptions such as:<\/p>\n<ul>\n<li data-pm-slice=\"0 0 []\">Where was the documentation for service X again?<\/li>\n<li data-pm-slice=\"0 0 []\">Do we already have a service\/library for this?<\/li>\n<li data-pm-slice=\"0 0 []\">Which environments is this deployed to?<\/li>\n<li data-pm-slice=\"0 0 []\">How do I deploy this to <em>k8s<\/em>. Is there a guideline or template?<\/li>\n<\/ul>\n<p data-pm-slice=\"0 0 []\">These may seem like minor hurdles, but when they accumulate across teams and over time, they hinder delivery and frustrate developers.<em> Backstage<\/em> addresses this by making software assets of the organization discoverable and making standards visible and reusable. Whether you are looking for an <em>API&#8217;s<\/em> spec, checking the <em>CI\/CD<\/em> status of your app or spinning up a new service using a golden path template, it\u2019s all accessible from <strong>a single unified platform<\/strong>.<\/p>\n<h1>Let\u2019s Get Our Hands Dirty<\/h1>\n<p data-pm-slice=\"0 0 []\">Let\u2019s see how we can create a golden path using <em>Backstage<\/em> templates, starting with a simple <em>API<\/em> project that gets published to <em>GitHub<\/em> and appears in the portal.<\/p>\n<h3 data-pm-slice=\"0 0 []\"><strong>Installing Backstage Locally<\/strong><\/h3>\n<p>To run <em>Backstage<\/em> locally, there are a few things we need to install like &#8220;<em>nvm<\/em>&#8220;, &#8220;<em>Node.js<\/em>&#8221; and &#8220;<em>Yarn<\/em>&#8220;. The following commands will help us to set up a standalone <em>Backstage<\/em> app quickly.<\/p>\n<pre>\u279c curl -o- https:\/\/raw.githubusercontent.com\/nvm-sh\/nvm\/v0.40.3\/install.sh | bash\r\n\u279c nvm install lts\/iron\r\n\u279c corepack enable\r\n\u279c yarn set version 4.4.1<\/pre>\n<blockquote><p><em><strong>NOTE<\/strong>: For other setup options, including Docker based approaches, you can <a href=\"https:\/\/backstage.io\/docs\/getting-started\/\" target=\"_blank\" rel=\"noopener\">check<\/a> the <a class=\"cursor-pointer\" target=\"_new\" rel=\"noopener\" data-start=\"710\" data-end=\"788\">official Backstage documentation<\/a>.<\/em><\/p><\/blockquote>\n<p>Once our env is ready, we can create the <em>Backstage<\/em>\u00a0app.<\/p>\n<pre>npx @backstage\/create-app<\/pre>\n<p>Then start the app!<\/p>\n<pre><span class=\"token-line\"><span class=\"token builtin class-name\">cd<\/span><span class=\"token plain\"> my-backstage-app <\/span><span class=\"token comment\"># your app name<\/span>\r\n<\/span><span class=\"token-line\"><span class=\"token function\">yarn<\/span><span class=\"token plain\"> start<\/span><\/span><\/pre>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-1-scaled.jpg\"><img decoding=\"async\" class=\"size-full wp-image-4724 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-1-scaled.jpg\" alt=\"\" width=\"2560\" height=\"1157\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-1-scaled.jpg 2560w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-1-300x136.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-1-1024x463.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-1-768x347.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-1-1536x694.jpg 1536w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-1-2048x925.jpg 2048w\" data-sizes=\"(max-width: 2560px) 100vw, 2560px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 2560px; --smush-placeholder-aspect-ratio: 2560\/1157;\" \/><\/a><\/p>\n<h3><strong>Getting Familiar with Backstage<\/strong><\/h3>\n<p data-pm-slice=\"0 0 []\">Before jumping into golden paths, let&#8217;s quickly explore some of the key features of <em>Backstage<\/em>.<\/p>\n<h4 data-pm-slice=\"0 0 []\"><strong>Software Catalog<\/strong><\/h4>\n<p data-pm-slice=\"0 0 []\">At its core, <em>Backstage<\/em> is powered by the <strong>Catalog<\/strong>, which is also the first thing we see when we open the portal. The catalog keeps track of all our software components like <em>services<\/em>, <em>websites<\/em>, <em>APIs<\/em>, <em>libraries<\/em>, and more. Each component is defined using a simple &#8220;<em>catalog-info.yaml<\/em>&#8221; manifest that typically lives alongside the source code in its repository. Once registered, these components become visible, searchable, and manageable through the portal.<\/p>\n<p>As i mentioned earlier, this is one of the easiest and most impactful ways to start your <em>DevEx<\/em> journey. By leveraging the catalog feature, you can bring instant structure and discoverability to your existing software assets right from day one.<\/p>\n<p data-pm-slice=\"1 1 []\">When you click on one of the catalog items, let\u2019s say the &#8220;<em>example-website<\/em>&#8221; item, you will see a detailed view of that component.<\/p>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-detail-scaled.jpg\"><img decoding=\"async\" class=\"size-full wp-image-4727 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-detail-scaled.jpg\" alt=\"\" width=\"2560\" height=\"1555\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-detail-scaled.jpg 2560w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-detail-300x182.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-detail-1024x622.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-detail-768x466.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-detail-1536x933.jpg 1536w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/backstage-catalog-detail-2048x1244.jpg 2048w\" data-sizes=\"(max-width: 2560px) 100vw, 2560px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 2560px; --smush-placeholder-aspect-ratio: 2560\/1555;\" \/><\/a><\/p>\n<p data-pm-slice=\"0 0 []\">This page gives us everything we need to know about the item like its metadata (which is fully customizable), ownership details (which becomes especially important in large organizations), source code location, technical documentation, linked <em>APIs<\/em>, <em>CI\/CD<\/em> status, and more. If the component exposes <em>APIs<\/em>, they can also be listed and documented right here, making it easier for other teams to discover, understand, and reuse them. This view can be also enriched with additional plugins like <em>ArgoCD<\/em>, <em>Kubernetes<\/em> and many others. We can even develop our own custom plugins to surface organization specific data or actions. You can explore all available plugins <em><a href=\"https:\/\/backstage.io\/plugins\" target=\"_blank\" rel=\"noopener\">here<\/a><\/em>.<\/p>\n<h4 data-pm-slice=\"0 0 []\"><strong>TechDocs<\/strong><\/h4>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/techdocs-scaled.jpg\"><img decoding=\"async\" class=\"size-full wp-image-4729 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/techdocs-scaled.jpg\" alt=\"\" width=\"2560\" height=\"1038\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/techdocs-scaled.jpg 2560w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/techdocs-300x122.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/techdocs-1024x415.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/techdocs-768x311.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/techdocs-1536x623.jpg 1536w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/techdocs-2048x830.jpg 2048w\" data-sizes=\"(max-width: 2560px) 100vw, 2560px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 2560px; --smush-placeholder-aspect-ratio: 2560\/1038;\" \/><\/a><\/p>\n<p data-pm-slice=\"0 0 []\">Another useful feature of <em>Backstage<\/em> is <strong>TechDocs<\/strong>, which brings documentation closer to the code and into the portal. It\u2019s based on <em>MkDocs<\/em>, so teams can write docs in <em>Markdown<\/em> and store them alongside the source code in the repository. Once integrated, the documentation becomes searchable and accessible right inside <em>Backstage<\/em>. This means developers no longer need to jump between tools to find or read internal docs.<\/p>\n<h4 data-pm-slice=\"0 0 []\"><strong>Software Templates<\/strong><\/h4>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/software-templates-scaled.jpg\"><img decoding=\"async\" class=\"size-full wp-image-4736 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/software-templates-scaled.jpg\" alt=\"\" width=\"2560\" height=\"1242\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/software-templates-scaled.jpg 2560w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/software-templates-300x146.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/software-templates-1024x497.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/software-templates-768x373.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/software-templates-1536x745.jpg 1536w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/software-templates-2048x994.jpg 2048w\" data-sizes=\"(max-width: 2560px) 100vw, 2560px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 2560px; --smush-placeholder-aspect-ratio: 2560\/1242;\" \/><\/a><\/p>\n<p data-pm-slice=\"0 0 []\">In addition to docs, <em>Backstage<\/em> also supports <strong>Software Templates<\/strong>, which allow teams to scaffold new projects <strong>quickly<\/strong> and <strong>consistently<\/strong>. These templates can be anything and be tailored to include organization&#8217;s preferred <em>tech stacks<\/em>, <em>standards<\/em>, <em>CI\/CD<\/em> <em>templates<\/em>, <em>repository structures<\/em> and even <em>security<\/em> and <em>compliance integrations<\/em>.<\/p>\n<p data-pm-slice=\"0 0 []\">And i like to call these <strong>golden paths<\/strong>,\u00a0predefined paths that give teams a solid foundation and help them start on the right foot from day one.<\/p>\n<h3 data-pm-slice=\"0 0 []\"><strong>Creating Golden Paths\/Software Templates<\/strong><\/h3>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/golden-paths-scaled.jpg\"><img decoding=\"async\" class=\"size-full wp-image-4740 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/golden-paths-scaled.jpg\" alt=\"\" width=\"2560\" height=\"1573\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/golden-paths-scaled.jpg 2560w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/golden-paths-300x184.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/golden-paths-1024x629.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/golden-paths-768x472.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/golden-paths-1536x944.jpg 1536w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/golden-paths-2048x1259.jpg 2048w\" data-sizes=\"(max-width: 2560px) 100vw, 2560px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 2560px; --smush-placeholder-aspect-ratio: 2560\/1573;\" \/><\/a><\/p>\n<p>When we talk about golden paths, we are referring to opinionated, predefined ways of building software that align with organizational standards and best practices.<\/p>\n<p>As i mentioned earlier in the article, golden paths are not restrictions. They are about enabling teams to reach their goals faster, in a consistent and compliant way. They are also a great mechanism for driving governance, security and compliance as enablers rather than blockers. When things baked into golden paths, <strong>adoption<\/strong> becomes natural by design.<\/p>\n<p>Golden paths can be anything that is <em>repeatable<\/em>, <em>useful<\/em>, and <em>aligned<\/em> with best practices:<\/p>\n<ul>\n<li>A microservice or frontend app scaffolded with standards like <em>CI\/CD<\/em>, <em>IAM<\/em>, and observability setups.<\/li>\n<li>A hardened infrastructure as code module with built-in security and compliance policies.<\/li>\n<li>Or even a sandbox environment template that lets teams experiment safely.<\/li>\n<\/ul>\n<p>In short, a golden path can be anything that helps your organization move faster, stay consistent, and build with confidence through <strong>enablement<\/strong> and developer <strong>self-service<\/strong>.<\/p>\n<p>In <em>Backstage<\/em>, software templates are the foundation for implementing these golden paths. They let us package everything from folder structure and config files to integrations and documentation into a reusable, self-service experience.<\/p>\n<p>Under the hood, <em>Backstage<\/em> uses a scaffolder engine that reads a simple manifest file to define each software template. This manifest controls what input variables are required from the user, what actions to run, and how the resulting template should be created and published to locations like <em>GitHub<\/em> or <em>Azure DevOps<\/em>.<\/p>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/nodejs-template-scaled.jpg\"><img decoding=\"async\" class=\"size-full wp-image-4742 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/nodejs-template-scaled.jpg\" alt=\"\" width=\"2560\" height=\"1160\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/nodejs-template-scaled.jpg 2560w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/nodejs-template-300x136.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/nodejs-template-1024x464.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/nodejs-template-768x348.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/nodejs-template-1536x696.jpg 1536w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/06\/nodejs-template-2048x928.jpg 2048w\" data-sizes=\"(max-width: 2560px) 100vw, 2560px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 2560px; --smush-placeholder-aspect-ratio: 2560\/1160;\" \/><\/a><\/p>\n<p>For example this &#8220;<em>Example Node.js Template<\/em>&#8221; form asks the user for basic input like the name of the component. Once submitted, <em>Backstage<\/em> scaffolds the project based on predefined instructions behind the scenes and publishes it to the selected <em>Git<\/em> location.<\/p>\n<h3>Template Manifest<\/h3>\n<p data-pm-slice=\"0 0 []\">Each <em>Backstage<\/em> software template is powered by a simple &#8220;<em>template.yaml<\/em>&#8221; manifest file. This <em>yaml<\/em> file acts as a blueprint that defines how the scaffolding process works. These templates are also stored in the &#8220;<em>Software Catalog<\/em>&#8221; under &#8220;<em>Templates<\/em>&#8221; kind.<\/p>\n<p data-pm-slice=\"0 0 []\">A typical template manifest includes these key sections:<\/p>\n<ul>\n<li data-pm-slice=\"0 0 []\">&#8220;<strong><em>metadata<\/em><\/strong>&#8221;\n<ul>\n<li data-pm-slice=\"0 0 []\">Defines the name, description, tags and ownership of the template.<\/li>\n<\/ul>\n<\/li>\n<li data-pm-slice=\"0 0 []\">&#8220;<strong><em>spec.type<\/em><\/strong>&#8221;\n<ul>\n<li data-pm-slice=\"0 0 []\">Defines what kind of software component the template will generate. Common values are &#8220;service&#8221;, &#8220;website&#8221;, &#8220;library&#8221; or custom types that reflect how an organization classifies software. This helps organize components consistently in the catalog and enables better filtering and discoverability.<\/li>\n<\/ul>\n<\/li>\n<li data-pm-slice=\"0 0 []\">&#8220;<em><strong>spec.lifecycle<\/strong><\/em>&#8221;\n<ul>\n<li data-pm-slice=\"0 0 []\">Indicates the stage of the component such as &#8220;experimental&#8221;, &#8220;production&#8221; or &#8220;deprecated&#8221;. This helps teams understand the maturity of the generated component.<\/li>\n<\/ul>\n<\/li>\n<li data-pm-slice=\"0 0 []\">&#8220;<em><strong>spec.parameters<\/strong><\/em>&#8221;\n<ul>\n<li data-pm-slice=\"0 0 []\">Declares the form inputs that users will fill out in the <em>UI.<\/em><\/li>\n<\/ul>\n<\/li>\n<li data-pm-slice=\"0 0 []\">&#8220;<em><strong>spec.steps<\/strong><\/em>&#8221;\n<ul>\n<li data-pm-slice=\"0 0 []\">The list of actions to perform such as fetching source files, templating them, publishing to <em>GitHub<\/em>\u00a0and so on. We will take a closer look at this shortly.<\/li>\n<\/ul>\n<\/li>\n<li data-pm-slice=\"0 0 []\">&#8220;<em><strong>spec.output<\/strong><\/em>&#8221;\n<ul>\n<li data-pm-slice=\"0 0 []\">Defines what should be shown to the user once the scaffolding is complete. Think of it like shortcuts, links to the <em>Git<\/em> repo of the generated project, and similar helpful outputs.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Here is a minimal example manifest:<\/p>\n<pre>apiVersion: scaffolder.backstage.io\/v1beta3\r\nkind: Template\r\nmetadata:\r\n  name: my-template\r\n  title: Title of the Template\r\n  description: Some details about what this template scaffolds\r\nspec:\r\n  owner: owning-team\r\n  type: service\r\n  parameters:\r\n    - title: Service Info\r\n      required:\r\n        - name\r\n      properties:\r\n        name:\r\n          type: string\r\n          title: Name of the service\r\n          description: Some information about this parameter\r\n  steps:\r\n    - id: fetch-base\r\n      name: Fetch base template\r\n      action: fetch:template\r\n      input:\r\n        url: .\/skeleton\r\n    - id: publish\r\n      name: Publish to GitHub\r\n      action: publish:github\r\n      input:\r\n        repoUrl: github.com\/my-org\/{{ parameters.name }}\r\n  output:\r\n    links:\r\n      - title: Source Code\r\n        url: '{{ steps.publish.output.repoUrl }}'\r\n<\/pre>\n<p data-pm-slice=\"0 0 []\">So far, we have discussed the importance of golden paths and briefly explored how a <em>Backstage<\/em> template is structured. Now, it\u2019s time to create one ourselves and register it as a template in <em>Backstage<\/em>.<\/p>\n<p data-pm-slice=\"0 0 []\">But before we jump into building our first template, let&#8217;s take a quick step to enable <em>GitHub<\/em> integration. This will allow <em>Backstage&#8217;s<\/em>\u00a0scaffolder engine to create and publish the generated project directly to a <em>GitHub<\/em> repository as part of the templating process. Of course <em>GitHub<\/em> is just one example. <em>Backstage<\/em> supports <em><a href=\"https:\/\/backstage.io\/docs\/integrations\/\" target=\"_blank\" rel=\"noopener\">other<\/a><\/em> source control providers as well, so it&#8217;s up to each organization to choose what fits their environment best.<\/p>\n<p data-pm-slice=\"0 0 []\">To enable the integration, first we need to create a <em>PAT<\/em> with the following scopes &#8220;repo&#8221;, &#8220;workflow&#8221;, and &#8220;admin:repo_hook&#8221;. Since <em>GitHub<\/em> integration is already configured in the &#8220;<em>app-config.yaml<\/em>&#8221; file under &#8220;<i>integrations: GitHub<\/i>&#8221; section using the &#8220;<em>${GITHUB_TOKEN}<\/em>&#8221; variable, all we need to do is to set this environment variable before running <em>Backstage<\/em>. In addition, if we you using <em>Node.js 20+, <\/em>set &#8220;<em>NODE_OPTIONS<\/em>&#8221; environment variable to avoid issues\u00a0with <em>Backstage&#8217;s<\/em> scaffolder.<\/p>\n<div>\n<pre>export GITHUB_TOKEN=\"YOUR_PAT_TOKEN\"\r\nexport NODE_OPTIONS=\"${NODE_OPTIONS:-} --no-node-snapshot\"<\/pre>\n<\/div>\n<blockquote><p><em><strong>NOTE<\/strong><\/em>: If you would like to avoid setting these variables manually, consider using the &#8220;<em>dotenv<\/em>&#8221; package to manage them in a &#8220;<em>.env<\/em>&#8221; file.<\/p><\/blockquote>\n<h3>Let&#8217;s Build a Golden Template<\/h3>\n<p>Imagine that we want to prepare a battle tested microservice <em>API<\/em> boilerplate that developers can use to spin up new services quickly without worrying about setting up the <em>API<\/em> structure, creating a repository, writing a <em>Dockerfile<\/em>, configuring <em>CI\/CD<\/em> pipelines, or integrating with <em>IAM<\/em> and observability stacks. In short, everything that our organization typically uses, packaged in a way that saves developers time and effort.<\/p>\n<p>For sake of the simplicity, I will keep things straightforward in this example. Let\u2019s start by creating a local repository, which we will later push to <em>GitHub<\/em>. I will call it &#8220;<em>sample-backstage-template<\/em>&#8220;. In the root of this repository, create a folder named &#8220;<em>skeleton<\/em>&#8220;. This is where we will place our boilerplate code that gets scaffolded into new projects.<\/p>\n<p>Now, let\u2019s create a <em>.NET 9 API<\/em> project inside the &#8220;<em>skeleton<\/em>&#8221; folder using the following command. Alternatively, you can use any existing boilerplate code you already have. For this example, I will call the <em>API<\/em> &#8220;<em>MyOrg.XToken<\/em>&#8220;.<\/p>\n<pre>dotnet new webapi -n MyOrg.XToken<\/pre>\n<p data-start=\"190\" data-end=\"342\">Inside the generated project folder, let\u2019s also define a <em>Dockerfile<\/em>.\u00a0You can use <em>Visual Studio<\/em> to generate one, or create it manually. After that, go back to the root of the &#8220;<em>skeleton<\/em>&#8221; folder and create a &#8220;<em>ci.yml<\/em>&#8221; file under the &#8220;<em>.github\/workflows<\/em>&#8221; directory. This will allow us to demonstrate that our golden <em>API<\/em> template includes a hardened <em>CI\/CD<\/em> pipeline out of the box.<\/p>\n<p data-start=\"190\" data-end=\"342\">Last but not least, create an empty &#8220;<em>README.md<\/em>&#8221; file under a &#8220;<em>docs<\/em>&#8221; folder.<\/p>\n<p data-start=\"190\" data-end=\"342\">Our folder structure should now look like this:<\/p>\n<pre>sample-backstage-template\r\n\u2514\u2500\u2500 skeleton\r\n    \u251c\u2500\u2500 .github\/workflows\/ci.yml\r\n    \u251c\u2500\u2500 docs\/README.md\r\n    \u251c\u2500\u2500 MyOrg.XToken\/\r\n    \u2514\u2500\u2500 MyOrg.XToken.sln\r\n<\/pre>\n<p>Now it\u2019s time to start tokenizing our .<em>NET<\/em> boilerplate code so that it can be reused across projects with different names, owners, and configurations. We will use a templating syntax like <strong><em>${{ values.parameterName }}<\/em><\/strong>\u00a0 to inject dynamic values into the generated project files.<\/p>\n<p data-pm-slice=\"1 1 []\">With that in mind, let\u2019s identify and tokenize the parts of our boilerplate code that should vary per project such as the project name, port number, folder and file names, <em>README<\/em> content, and so on. In this example, I\u2019m going to replace all occurrences of &#8220;<em>XToken<\/em>&#8221; in the .<em>NET<\/em> boilerplate and also parameterize the exposed port in the <em>Dockerfile <\/em>as shown below.<\/p>\n<pre>FROM mcr.microsoft.com\/dotnet\/aspnet:9.0 AS base\r\nWORKDIR \/app\r\nEXPOSE ${{ values.port }}\r\n\r\nENV ASPNETCORE_URLS=http:\/\/+:${{ values.port }}\r\n\r\nUSER app\r\nFROM --platform=$BUILDPLATFORM mcr.microsoft.com\/dotnet\/sdk:9.0 AS build\r\nARG configuration=Release\r\nWORKDIR \/src\r\nCOPY [\"MyOrg.${{ values.projectName }}\/MyOrg.${{ values.projectName }}.csproj\", \"MyOrg.${{ values.projectName }}\/\"]\r\nRUN dotnet restore \"MyOrg.${{ values.projectName }}\/MyOrg.${{ values.projectName }}.csproj\"\r\nCOPY . .\r\nWORKDIR \"\/src\/MyOrg.${{ values.projectName }}\"\r\nRUN dotnet build \"MyOrg.${{ values.projectName }}.csproj\" -c $configuration -o \/app\/build\r\n\r\nFROM build AS publish\r\nARG configuration=Release\r\nRUN dotnet publish \"MyOrg.${{ values.projectName }}.csproj\" -c $configuration -o \/app\/publish \/p:UseAppHost=false\r\n\r\nFROM base AS final\r\nWORKDIR \/app\r\nCOPY --from=publish \/app\/publish .\r\nENTRYPOINT [\"dotnet\", \"MyOrg.${{ values.projectName }}.dll\"]<\/pre>\n<p><em>README.md<\/em><\/p>\n<pre># MyOrg.${{ values.projectName }}\r\nThis service was generated using the golden path template.<\/pre>\n<p><em>ci.yaml<\/em><\/p>\n<pre>name: ci\r\n\r\non:\r\n  push:\r\n    branches:\r\n      - main\r\n  pull_request:\r\n\r\njobs:\r\n  docker-build:\r\n    runs-on: ubuntu-latest\r\n\r\n    steps:\r\n      - name: Checkout source\r\n        uses: actions\/checkout@v3\r\n\r\n      - name: Set up Docker Buildx\r\n        uses: docker\/setup-buildx-action@v2\r\n\r\n      - name: Build Docker image\r\n        run: |\r\n          docker build -t myorg\/MyOrg.${{ values.projectName }}:${{ '${{ github.sha }}' }} .<\/pre>\n<p>As you can see, for the project name I used &#8220;<em>${{ values.projectName }}<\/em>&#8221; and for the port &#8220;<em>${{ values.port }}<\/em>&#8220;. Later on, we will define these values in our <em>Backstage<\/em> template manifest and pass them to the scaffolder engine.<\/p>\n<p>In addition to tokenizing the boilerplate code itself, we also want our generated project to include a dynamic &#8220;<em>catalog-info.yaml<\/em>&#8221; file. As mentioned earlier, this file defines the metadata that <em>Backstage<\/em> uses to register and display the component in the software catalog. And just like we did in the codebase, we can inject template values here as well to make the metadata dynamic and reusable.<\/p>\n<p><em>catalog-info.yaml<\/em><\/p>\n<pre>apiVersion: backstage.io\/v1alpha1\r\nkind: Component\r\nmetadata:\r\n  name: MyOrg.${{ values.projectName }}\r\n  description: MyOrg.${{ values.projectName }} project.\r\n  tags:\r\n    - dotnet\r\n    - api\r\n    - microservice\r\n    - ${{ values.owner }}\r\n  annotations:\r\n    backstage.io\/techdocs-ref: dir:.\r\nspec:\r\n  type: service\r\n  lifecycle: experimental\r\n  owner: ${{ values.owner }}\r\n<\/pre>\n<p data-pm-slice=\"0 0 []\">Here,<\/p>\n<ul>\n<li data-pm-slice=\"0 0 []\">Inside the &#8220;<strong><em>metadata<\/em><\/strong>&#8221; section, we have defined the &#8220;<strong><em>name<\/em><\/strong>&#8221; and the &#8220;<strong><em>description<\/em><\/strong>&#8221; of the component, along with a few meaningful tags. Tags play an important role in improving the discoverability and organization of catalog entities within <em>Backstage<\/em>.<\/li>\n<li data-pm-slice=\"0 0 []\">The &#8220;<strong><em>type<\/em><\/strong>&#8221; is set to &#8220;<strong><em>service<\/em><\/strong>&#8221; which indicates that this component is a backend service.<\/li>\n<li data-pm-slice=\"0 0 []\">The &#8220;<strong><em>lifecycle<\/em><\/strong>&#8221; is set to &#8220;<strong><em>experimental<\/em><\/strong>&#8221; which helps teams understand the maturity of the project. You can change this later to values like &#8220;<strong><em>production<\/em><\/strong>&#8221; based on your lifecycle policies.<\/li>\n<li data-pm-slice=\"0 0 []\">The &#8220;<strong><em>owner<\/em><\/strong>&#8221; field is important for access control, visibility and routing issues to the right team. We will pass this dynamically during scaffolding.<\/li>\n<li data-pm-slice=\"0 0 []\">Last but not least, with the &#8220;<em>backstage.io\/techdocs-ref: dir:.<\/em>&#8221; annotation, we tell <em>Backstage<\/em> where to find the docs like <em>README.md<\/em>,<em> mkdocs.yml<\/em> and others for generating and displaying <em>TechDocs<\/em> for this component.<\/li>\n<\/ul>\n<p>Now that we have completed our sample skeleton and it&#8217;s time to define the template manifest. This manifest tells <em>Backstage<\/em> how to scaffold the project, what parameters to ask from the user, what files to generate and what steps to run during the scaffolding process.<\/p>\n<p>So let&#8217;s create a <em>template.yaml <\/em>file in the root directory of the &#8220;<em>sample-backstage-template<\/em>&#8221; repository.<\/p>\n<pre>apiVersion: scaffolder.backstage.io\/v1beta3\r\nkind: Template\r\nmetadata:\r\n  name: dotnet-api-template\r\n  title: .NET 9 API Template\r\n  description: Scaffolds a .NET 9 Web API project with Dockerfile and CI\r\n  tags:\r\n    - dotnet\r\n    - api\r\n    - microservice\r\n    - starter-api-app\r\n  annotations:\r\n    backstage.io\/techdocs-ref: dir:.\r\nspec:\r\n  type: service\r\n  lifecycle: experimental\r\n  owner: user:guest\r\n  parameters:\r\n    - title: .NET API project information\r\n      required:\r\n        - projectName\r\n        - port\r\n        - owner\r\n      properties:\r\n        projectName:\r\n          title: Project Name\r\n          type: string\r\n          description: Unique name of the .NET API project.\r\n        port:\r\n          title: Port\r\n          type: number\r\n          description: Port the API will run on (e.g. 5000)\r\n        owner:\r\n          title: Team Name\r\n          type: string\r\n          description: Name of the team that will own this service.\r\n  steps:\r\n    - id: fetch-base\r\n      name: Fetch Base\r\n      action: fetch:template\r\n      input:\r\n        url: .\/skeleton\r\n        values:\r\n          projectName: ${{ parameters.projectName }}\r\n          port: ${{ parameters.port }}\r\n          owner: ${{ parameters.owner }}\r\n\r\n    - id: publish\r\n      name: Publish to GitHub\r\n      action: publish:github\r\n      input:\r\n        repoUrl: github.com?owner=YOUR_GITHUB_USERNAME&amp;repo=${{ parameters.projectName }}\r\n        defaultBranch: 'main'\r\n\r\n    - id: register\r\n      name: Register to Catalog\r\n      action: catalog:register\r\n      input:\r\n        repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}\r\n        catalogInfoPath: '\/catalog-info.yaml'\r\n\r\n  output:\r\n    links:\r\n      - title: Go to generated project\r\n        url: https:\/\/github.com\/YOUR_GITHUB_USERNAME\/${{ parameters.projectName }}<\/pre>\n<p>At a high level, in this manifest,<\/p>\n<ul>\n<li data-pm-slice=\"0 0 []\">Inside the &#8220;<strong><em>metadata<\/em><\/strong>&#8221; section, we have defined the meaningful name, description and tags for this template to make it easily discoverable in <em>Backstage<\/em>.<\/li>\n<li data-pm-slice=\"0 0 []\">Also set the &#8220;<em><strong>lifecycle<\/strong><\/em>&#8221; to &#8220;<em>experimental<\/em>&#8221; as an example for this template, and assigned the &#8220;<em><strong>ownership<\/strong><\/em>&#8221; to &#8220;<em>user:guest<\/em>&#8220;, which is the default guest user in <em>Backstage<\/em>. If we had defined a team like the Platform Team, we could have used that instead.<\/li>\n<li>&#8220;<strong><em>parameters<\/em><\/strong>&#8220;: these are the dynamic inputs we expect from the user like project name, port and owning team. These will be used to tokenize the boilerplate during generation. <em>Backstage<\/em> provides a rich set of <strong>built-in field types<\/strong> like text, number, select, multiselect with validation capabilities. In addition to the build-in types, we can extend the form with <strong>custom input fields<\/strong>. For example you might want to fetch team names or repository names dynamically from internal <em>APIs<\/em>, offer different autocomplete suggestions. For more details about available input types and validation options, you can check the official documentation <em><a href=\"https:\/\/backstage.io\/docs\/features\/software-templates\/input-examples\" target=\"_blank\" rel=\"noopener\">here<\/a><\/em>.<\/li>\n<li>&#8220;<strong><em>steps<\/em><\/strong>&#8220;: this is the sequence of actions <em>Backstage<\/em> performs to scaffold the new project. <em>Backstage<\/em> scaffolder comes with a rich set of <strong>built-in actions<\/strong> that cover common automation needs. So in our case:\n<ul>\n<li>&#8220;<strong><em>fetch-base<\/em><\/strong>&#8220;: pulls in the boilerplate code from the skeleton folder and applies the input parameters to replace the tokenized placeholders in the code. This is how the code gets customized per user input.<\/li>\n<li>&#8220;<strong><em>publish:github<\/em><\/strong>&#8220;: pushes the generated code to <em>GitHub<\/em> using the given repo name.<\/li>\n<li>&#8220;<strong><em>catalog:register<\/em><\/strong>&#8220;: registers the newly scaffolded project in <em>Backstage\u2019s<\/em> software catalog so it becomes immediately discoverable.<\/li>\n<li>You can explore these built-in actions directly from the <em>Backstage<\/em> <em>UI<\/em> by going to: &#8220;<em>Create &gt; three dots menu in the top right corner &gt; Installed Actions<\/em>&#8220;. This panel lists all the available registered actions and it&#8217;s great way to explore what&#8217;s possible without writing any code. <em>Backstage<\/em> also allows you to write custom actions to extend scaffolder&#8217;s capabilities like integrating with internal <em>APIs<\/em> and etc. By combining built-in and custom actions the scaffolder becomes a powerful automation engine tailored to your organization\u2019s specific workflows. You can refer to the <em><a href=\"https:\/\/backstage.io\/docs\/features\/software-templates\/writing-custom-actions\/\" target=\"_blank\" rel=\"noopener\">action docs<\/a><\/em> for a detailed guide.<\/li>\n<\/ul>\n<\/li>\n<li>&#8220;<strong><em>output<\/em><\/strong>&#8220;: once the project is generated, we show useful links like the link to the newly created <em>GitHub<\/em> repository so that users can quickly access their new service.<\/li>\n<\/ul>\n<p>Now, let\u2019s also define a <em>README.md<\/em> file under a &#8220;<em>docs<\/em>&#8221; folder in the root directory of the template repository. This will serve as documentation for the template itself and can also be used by <em>TechDocs<\/em> to generate documentation in <em>Backstage<\/em>.<\/p>\n<p><em>README.md<\/em><\/p>\n<pre># dotnet-api-template\r\nScaffolds a .NET 9 Web API project with Dockerfile and CI<\/pre>\n<p data-pm-slice=\"0 0 []\">With the template definition in place, we have completed the development of the golden template. Now before going to register this template in the software catalog, we can also validate and preview how it behaves within <em>Backstage<\/em>.<\/p>\n<p data-pm-slice=\"0 0 []\">To do that, you can use the build-in template editor feature in the scaffolder <em>UI<\/em> by navigating to &#8220;<em>Create &gt; three dots menu in the top right corner &gt; Manage Templates &gt; Load Template Directory<\/em>&#8220;.<\/p>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-editor-backstage-gokhan-gokalp.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-4760 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-editor-backstage-gokhan-gokalp.jpg\" alt=\"\" width=\"1796\" height=\"1187\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-editor-backstage-gokhan-gokalp.jpg 1796w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-editor-backstage-gokhan-gokalp-300x198.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-editor-backstage-gokhan-gokalp-1024x677.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-editor-backstage-gokhan-gokalp-768x508.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-editor-backstage-gokhan-gokalp-1536x1015.jpg 1536w\" data-sizes=\"(max-width: 1796px) 100vw, 1796px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1796px; --smush-placeholder-aspect-ratio: 1796\/1187;\" \/><\/a><\/p>\n<p data-pm-slice=\"0 0 []\">This feature allows us to load a template directly from our local file system and interactively fill out the form and validate input behavior. This is very handy when we are actively developing and iterating on the template, as it provides quick feedback without modifying the actual catalog.<\/p>\n<p data-pm-slice=\"0 0 []\">The final step is now to make our template discoverable within <em>Backstage<\/em> so that we can start using it.<\/p>\n<h3>Registering the Template in Backstage<\/h3>\n<p data-pm-slice=\"0 0 []\"><em>Backstage<\/em> provides a few different ways to register templates in the software catalog. The most straightforward method is through the scaffolder <em>UI<\/em> by navigating to the &#8220;<em>Create &gt; Register Existing Component<\/em>&#8221; page. Then, paste the <em>URL<\/em> of the template.yaml file (for example a <em>GitHub URL<\/em>). <em>Backstage<\/em> will fetch the file, validate the manifest and guide us through registration process.<\/p>\n<blockquote>\n<p data-pm-slice=\"0 0 []\"><em><strong>NOTE<\/strong><\/em>:\u00a0In order to register a template through the <em>UI<\/em>, &#8220;<em>Template<\/em>&#8221; must be allowed in the catalog rules defined in &#8220;<em>app-config.yaml<\/em>&#8220;.<\/p>\n<\/blockquote>\n<p>The other option is to add the template to the static catalog configuration file or directly in the &#8220;<em>app-config.yaml<\/em>&#8221; file as shown below.<\/p>\n<pre>catalog:\r\n  rules:\r\n    - allow: [Component, System, API, Resource, Location, Template, User, Group]\r\n  locations:\r\n    - type: url \r\n      target: https:\/\/YOUR_TEMPLATE_REPOSITORY_URL\/template.yaml\r\n<\/pre>\n<p>This is especially useful for organization wide templates maintained by platform teams. Additionally, you can maintain a separate catalog configuration file in a shared repository allowing others in the organization to <strong>contribute<\/strong> by creating pull requests to add the templates they develop.<\/p>\n<p>So, for simplicity, I&#8217;m going to add the template directly in the &#8220;<em>app-config.yaml<\/em>&#8221; file as shown above, and then restart <em>Backstage<\/em>. After restarting, navigate to the catalog homepage at &#8220;<em>http:\/\/localhost:3000\/catalog<\/em>&#8221; and filter by &#8220;<em>Kind=Template<\/em>&#8220;. We should now see our &#8220;.<em>NET 9 API Template<\/em>&#8221; listed. Click on it to view its details.<\/p>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-in-catalog-gokhan-gokalp.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-4763 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-in-catalog-gokhan-gokalp.jpg\" alt=\"\" width=\"1802\" height=\"1217\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-in-catalog-gokhan-gokalp.jpg 1802w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-in-catalog-gokhan-gokalp-300x203.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-in-catalog-gokhan-gokalp-1024x692.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-in-catalog-gokhan-gokalp-768x519.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-in-catalog-gokhan-gokalp-1536x1037.jpg 1536w\" data-sizes=\"(max-width: 1802px) 100vw, 1802px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1802px; --smush-placeholder-aspect-ratio: 1802\/1217;\" \/><\/a><\/p>\n<p>Here, we can see some basic details about our golden template, such as its description, intended purpose, owner, maturity level, and more.<\/p>\n<p>Now that our template is registered, let\u2019s walk through how to scaffold a new project by using it.<\/p>\n<h3>Scaffolding a Project<\/h3>\n<p>If we click the &#8220;<em>Launch Template<\/em>&#8221; button, we will be taken to the &#8220;<em>Create New Component<\/em>&#8221; page, where we can use this template to scaffold a new <em>.NET 9 API<\/em>. Alternatively, we can simply click the &#8220;<em>Create<\/em>&#8221; button from the left menu and select the template from the list.<\/p>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/scaffold-new-component-gokhan-gokalp.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-4764 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/scaffold-new-component-gokhan-gokalp.jpg\" alt=\"\" width=\"1810\" height=\"978\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/scaffold-new-component-gokhan-gokalp.jpg 1810w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/scaffold-new-component-gokhan-gokalp-300x162.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/scaffold-new-component-gokhan-gokalp-1024x553.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/scaffold-new-component-gokhan-gokalp-768x415.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/scaffold-new-component-gokhan-gokalp-1536x830.jpg 1536w\" data-sizes=\"(max-width: 1810px) 100vw, 1810px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1810px; --smush-placeholder-aspect-ratio: 1810\/978;\" \/><\/a><\/p>\n<p>As you can see, these are the parameters we defined in the template. Let\u2019s fill them in and click the \u201c<em>REVIEW<\/em>\u201d button. I will be using the following values:<\/p>\n<ul>\n<li><strong>Project Name<\/strong>: Search.API<\/li>\n<li><strong>Port<\/strong>: 5000<\/li>\n<li><strong>Team Name<\/strong>: guests<\/li>\n<\/ul>\n<p>On the review page, you will see the values that the scaffolder engine is going to use. If everything looks good, click the \u201c<em>CREATE<\/em>\u201d button.<\/p>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-gokhan-gokalp.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-4766 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-gokhan-gokalp.jpg\" alt=\"\" width=\"1807\" height=\"1217\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-gokhan-gokalp.jpg 1807w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-gokhan-gokalp-300x202.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-gokhan-gokalp-1024x690.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-gokhan-gokalp-768x517.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-gokhan-gokalp-1536x1034.jpg 1536w\" data-sizes=\"(max-width: 1807px) 100vw, 1807px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1807px; --smush-placeholder-aspect-ratio: 1807\/1217;\" \/><\/a><\/p>\n<p>On this template run page, we can see couple of useful information. The task <em>ID<\/em> of the run is shown for reference and for future debugging in case something goes wrong. Logs display the step by step progress of the scaffolding process. Shortcuts allow users to easily navigate to resources such as the generated <em>Git<\/em> repository in our case. There is also a set of tabs that show which actions were executed and their statuses during the run.<\/p>\n<p>Now, if we click the &#8220;<em>GO TO GENERATED PROJECT<\/em>&#8221; shortcut, we will be redirected to the <em>GitHub<\/em> repository where the project has been created.<\/p>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/github-output-gokhan-gokalp.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-4767 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/github-output-gokhan-gokalp.jpg\" alt=\"\" width=\"1162\" height=\"765\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/github-output-gokhan-gokalp.jpg 1162w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/github-output-gokhan-gokalp-300x198.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/github-output-gokhan-gokalp-1024x674.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/github-output-gokhan-gokalp-768x506.jpg 768w\" data-sizes=\"(max-width: 1162px) 100vw, 1162px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1162px; --smush-placeholder-aspect-ratio: 1162\/765;\" \/><\/a><\/p>\n<p>So, in my case, the project has been successfully scaffolded and all the placeholder tokens have been replaced. From a developer\u2019s perspective, this means I\u2019m now ready to focus on <strong>implementing the actual business logic<\/strong>, rather than spending time on setting up the project structure, <em>CI\/CD<\/em> pipeline or other boilerplate tasks.<\/p>\n<p>Now, if we go back to the catalog homepage in <em>Backstage<\/em>, we can see that our newly generated project has also been registered in <em>Backstage\u2019s<\/em> software catalog. If we click on it, we can also view its metadata, including information such as the description, owner, lifecycle and any tags defined in the template. If the catalog page has integrations configured like <em>CI\/CD<\/em> tools or <em>APIs<\/em> linked with <em>OpenAPI<\/em> specs, the component page will show extra information in tabs such as <em>CI\/CD<\/em> and <em>API<\/em>. This helps developers better understand and access different information in one place.<\/p>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/catalog-detail-new-component-gokhan-gokalp.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-4768 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/catalog-detail-new-component-gokhan-gokalp.jpg\" alt=\"\" width=\"1807\" height=\"1166\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/catalog-detail-new-component-gokhan-gokalp.jpg 1807w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/catalog-detail-new-component-gokhan-gokalp-300x194.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/catalog-detail-new-component-gokhan-gokalp-1024x661.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/catalog-detail-new-component-gokhan-gokalp-768x496.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/catalog-detail-new-component-gokhan-gokalp-1536x991.jpg 1536w\" data-sizes=\"(max-width: 1807px) 100vw, 1807px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1807px; --smush-placeholder-aspect-ratio: 1807\/1166;\" \/><\/a><\/p>\n<p>Before wrapping up, let\u2019s also go back to the &#8220;<em>Create<\/em>&#8221; page, click on the three dots in the upper right corner and select the &#8220;<em>Task List<\/em>&#8220;. This will take us to a page that displays all template runs. This page is especially useful for platform teams or those responsible for maintaining <em>Backstage<\/em>, as it provides visibility into all scaffolding executions and helps in troubleshooting issues when other teams encounter problems during template runs.<\/p>\n<p><a href=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-page.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-4769 lazyload\" data-src=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-page.jpg\" alt=\"\" width=\"1812\" height=\"597\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-page.jpg 1812w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-page-300x99.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-page-1024x337.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-page-768x253.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/template-run-page-1536x506.jpg 1536w\" data-sizes=\"(max-width: 1812px) 100vw, 1812px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1812px; --smush-placeholder-aspect-ratio: 1812\/597;\" \/><\/a><\/p>\n<h1 data-start=\"811\" data-end=\"1337\"><\/h1>\n<h1 data-start=\"811\" data-end=\"1337\">Wrapping Up<\/h1>\n<p data-start=\"811\" data-end=\"1337\">In this article, we have walked through how to use the <em>Backstage<\/em> scaffolder to bootstrap new projects efficiently by using pre-defined templates that enforce standards and reduce repetitive setup work. With the ability to automatically generate code, pipelines, metadata, and more, <em>Backstage<\/em> empowers development teams to focus on what matters most. As a result, organizations can achieve <strong>faster onboarding<\/strong>, <strong>better consistency<\/strong>, and <strong>improved developer experience<\/strong> across the board.<\/p>\n<p data-start=\"811\" data-end=\"1337\">Whether you are part of a platform team or a developer just getting started, understanding the scaffolder and catalog workflows is key to unlocking <em>Backstage&#8217;s<\/em> potential. And as we have seen, even without a full internal developer platform in place, <em>Backstage<\/em> can deliver immediate value through <strong>standardization<\/strong>, <strong>discoverability<\/strong> and a well-structured scaffolder setup that lays the groundwork for <strong>golden paths<\/strong>.<\/p>\n<h2 data-start=\"1339\" data-end=\"1502\">References<\/h2>\n<blockquote><p><em>https:\/\/github.com\/GokGokalp\/sample-backstage-template<br \/>\nhttps:\/\/backstage.io\/docs\/overview\/what-is-backstage<br \/>\nhttps:\/\/platformengineering.org\/blog\/what-is-platform-engineering<br \/>\n<\/em><\/p><\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>As an architect involved in platform engineering and DevEx transformation within a large-scale organization for the past few years, I\u2019ve seen firsthand how developer experience directly shapes not just the speed and quality of software delivery, but also how effectively teams can adopt governance, security,&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/gokhan-gokalp.com\/tr\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/\">Devam\u0131n\u0131 okuyun<span class=\"screen-reader-text\">DevEx Series 01: Creating Golden Paths with Backstage, Developer Self-Service Without Losing Control<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":4773,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,714],"tags":[713,722,715,717,716,659,719,721,720,718],"class_list":["post-4708","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net","category-platform-engineering","tag-net-9","tag-automation","tag-backstage","tag-developer-experience","tag-devex","tag-dotnet","tag-idp","tag-internal-developer-platform","tag-internal-developer-portal","tag-platform-engineering","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"tr","enabled_languages":["en","tr"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"tr":{"title":false,"content":false,"excerpt":false}}},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>DevEx Series 01: Creating Golden Paths with Backstage, Developer Self-Service Without Losing Control - G\u00f6khan G\u00f6kalp<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"DevEx Series 01: Creating Golden Paths with Backstage, Developer Self-Service Without Losing Control - G\u00f6khan G\u00f6kalp\" \/>\n<meta property=\"og:url\" content=\"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/\" \/>\n<meta property=\"og:site_name\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n<meta property=\"article:published_time\" content=\"2025-08-01T19:58:33+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/devex-gokhan-gokalp-cover.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"675\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"25 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\\\/\"},\"author\":{\"name\":\"G\u00f6khan G\u00f6kalp\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"headline\":\"DevEx Series 01: Creating Golden Paths with Backstage, Developer Self-Service Without Losing Control\",\"datePublished\":\"2025-08-01T19:58:33+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\\\/\"},\"wordCount\":4440,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"image\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2025\\\/07\\\/devex-gokhan-gokalp-cover.jpg\",\"keywords\":[\".net 9\",\"automation\",\"backstage\",\"developer experience\",\"devex\",\"dotnet\",\"idp\",\"internal developer platform\",\"internal developer portal\",\"platform engineering\"],\"articleSection\":[\".NET\",\"Platform Engineering\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/gokhan-gokalp.com\\\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\\\/\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\\\/\",\"name\":\"DevEx Series 01: Creating Golden Paths with Backstage, Developer Self-Service Without Losing Control - G\u00f6khan G\u00f6kalp\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2025\\\/07\\\/devex-gokhan-gokalp-cover.jpg\",\"datePublished\":\"2025-08-01T19:58:33+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\\\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/gokhan-gokalp.com\\\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\\\/#primaryimage\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2025\\\/07\\\/devex-gokhan-gokalp-cover.jpg\",\"contentUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2025\\\/07\\\/devex-gokhan-gokalp-cover.jpg\",\"width\":1200,\"height\":675},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/gokhan-gokalp.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"DevEx Series 01: Creating Golden Paths with Backstage, Developer Self-Service Without Losing Control\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#website\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/\",\"name\":\"G\u00f6khan G\u00f6kalp\",\"description\":\"C# &amp; Python lover\",\"publisher\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/gokhan-gokalp.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\",\"name\":\"G\u00f6khan G\u00f6kalp\",\"pronouns\":\"he\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\",\"contentUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\",\"caption\":\"G\u00f6khan G\u00f6kalp\"},\"logo\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\"},\"sameAs\":[\"https:\\\/\\\/gokhan-gokalp.com\"],\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/tr\\\/author\\\/gok-gokalp\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"DevEx Series 01: Creating Golden Paths with Backstage, Developer Self-Service Without Losing Control - G\u00f6khan G\u00f6kalp","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/","og_locale":"tr_TR","og_type":"article","og_title":"DevEx Series 01: Creating Golden Paths with Backstage, Developer Self-Service Without Losing Control - G\u00f6khan G\u00f6kalp","og_url":"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/","og_site_name":"G\u00f6khan G\u00f6kalp","article_published_time":"2025-08-01T19:58:33+00:00","og_image":[{"width":1200,"height":675,"url":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/devex-gokhan-gokalp-cover.jpg","type":"image\/jpeg"}],"author":"G\u00f6khan G\u00f6kalp","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"G\u00f6khan G\u00f6kalp","Tahmini okuma s\u00fcresi":"25 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/#article","isPartOf":{"@id":"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/"},"author":{"name":"G\u00f6khan G\u00f6kalp","@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"headline":"DevEx Series 01: Creating Golden Paths with Backstage, Developer Self-Service Without Losing Control","datePublished":"2025-08-01T19:58:33+00:00","mainEntityOfPage":{"@id":"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/"},"wordCount":4440,"commentCount":1,"publisher":{"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"image":{"@id":"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/#primaryimage"},"thumbnailUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/devex-gokhan-gokalp-cover.jpg","keywords":[".net 9","automation","backstage","developer experience","devex","dotnet","idp","internal developer platform","internal developer portal","platform engineering"],"articleSection":[".NET","Platform Engineering"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/","url":"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/","name":"DevEx Series 01: Creating Golden Paths with Backstage, Developer Self-Service Without Losing Control - G\u00f6khan G\u00f6kalp","isPartOf":{"@id":"https:\/\/gokhan-gokalp.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/#primaryimage"},"image":{"@id":"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/#primaryimage"},"thumbnailUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/devex-gokhan-gokalp-cover.jpg","datePublished":"2025-08-01T19:58:33+00:00","breadcrumb":{"@id":"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/"]}]},{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/#primaryimage","url":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/devex-gokhan-gokalp-cover.jpg","contentUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2025\/07\/devex-gokhan-gokalp-cover.jpg","width":1200,"height":675},{"@type":"BreadcrumbList","@id":"https:\/\/gokhan-gokalp.com\/devex-series-01-creating-golden-paths-with-backstage-developer-self-service-without-losing-control\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/gokhan-gokalp.com\/"},{"@type":"ListItem","position":2,"name":"DevEx Series 01: Creating Golden Paths with Backstage, Developer Self-Service Without Losing Control"}]},{"@type":"WebSite","@id":"https:\/\/gokhan-gokalp.com\/#website","url":"https:\/\/gokhan-gokalp.com\/","name":"G\u00f6khan G\u00f6kalp","description":"C# &amp; Python lover","publisher":{"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/gokhan-gokalp.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe","name":"G\u00f6khan G\u00f6kalp","pronouns":"he","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659","url":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659","contentUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659","caption":"G\u00f6khan G\u00f6kalp"},"logo":{"@id":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659"},"sameAs":["https:\/\/gokhan-gokalp.com"],"url":"https:\/\/gokhan-gokalp.com\/tr\/author\/gok-gokalp\/"}]}},"_links":{"self":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/4708","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/comments?post=4708"}],"version-history":[{"count":67,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/4708\/revisions"}],"predecessor-version":[{"id":4793,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/4708\/revisions\/4793"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/media\/4773"}],"wp:attachment":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/media?parent=4708"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/categories?post=4708"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/tags?post=4708"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}