Let’s be honest - most Internal Developer Platforms (IDPs) end up as dashboards with scattered data. They promise a lot: better developer experience, less cognitive overhead, smoother onboarding. But if you peek under the hood of many setups, they’re just collections of disconnected resources with no meaningful structure.
Why does this happen? Most platform teams start by integrating the existing tools like CI/CD pipelines, code repositories, registries, infrastructure automation, etc. They focus on integration first, thinking they can figure out the structure later. But without a proper mental model of what you want, you end up with a disconnected system.
Here’s the core problem: the data model is usually an afterthought.
If you want your platform to actually deliver on its promise, you need to start with a clear understanding of what you’re modelling. In this blog post, we’ll walk through an approach that puts the Service Catalog at the center of everything, because in most modern engineering orgs, that’s exactly how it works in practice.
Think about how work flows through your organization. Features, bugs, and incidents don’t get assigned to random teams or repos - they’re tied to services and *applications. These are the atomic units of the value chain - what you deploy, monitor, secure, and support.
And yet, we’ve seen plenty of IDPs built around “projects,” “environments,” or even “repos.” These models break down fast, especially as orgs scale. You end up with duplication, missed ownership, unclear dependencies, and a general sense of drift.
A service catalog gives you a solid and reliable anchor that reflects the reality of how your org thinks, ships, and operates. When you model around services, everything else - deployments, incidents, metrics, dependencies - naturally falls into place.
Here’s the model we’ve seen work with an enterprise client. It’s simple, but powerful.
Every core flow - deployments, SLOs, incidents, ownership, on-call, cost tracking — should start with a Service. This creates clear golden paths for developers to self-serve their infrastructure needs.
In practice, a “service” could be:
payment-service
dashboard-web
auth-lib
user-db
Each of these maps belongs to a Component in your catalog (type: service
, type: library
, type: database
, etc.).
Example: In Git, you might have:
git@company/payment-service.git
→ Component: payment-service
(type: service
)git@company/auth-lib.git
→ Component: auth-lib
(type: library
)git@company/user-db.git
→ Component: user-db
(type: database
)In Backstage, these would all be cataloged under kind: Component
with different type
values.
Every service should have a clear owning team. Teams are responsible for:
But ownership can sometimes be tricky - maybe a service was created by one team and is maintained by another. That’s why explicitly mapping teams to services is critical.
Example:
payment-service
→ Owned by payments-platform-team
auth-lib
→ Owned by security-engineering
user-db
→ Shared by user-platform
and infra-data
This allows alerts, dashboards, and escalations to route correctly.
While teams own services, individual users still matter for:
Users should always be connected through teams, not directly to services, to maintain a clean ownership model that avoids fragmentation.
Example:
john@company.com
→ Member of payments-platform-team
alice@company.com
→ Member of security-engineering
So when auth-lib
has a production issue, the incident escalation goes to security-engineering
, not Alice directly.
Products are customer-facing value bundles. A product typically spans multiple services and is how leadership thinks about capabilities.
Example:
cart-service
payment-service
inventory-service
auth-lib
user-db
login-ui
This view helps with roadmap planning, measuring product-level uptime, and tying tech metrics to business outcomes.
A “customer” can be:
Knowing which services impact which customers is essential for:
Example:
inventory-service
→ Impacts: E-commerce Customers
event-ingestion-service
→ Impacts: Data Platform Team
auth-lib
→ Impacts: All internal services requiring authenticationWhat ties this model together is a simple principle: everything revolves around the service. It’s the node that connects all the others, creating clear golden paths for developers to self-serve their infrastructure needs with minimal cognitive load, which is exactly how successful platform teams approach their Internal Developer Platform as a product.
There are a few common mistakes we’ve seen (and made) when modeling an IDP:
“Scalable” doesn’t only mean it can hold more data. It also means the model keeps working as your organization gets more complex.
That includes:
If your IDP model needs rework every time your org evolves, it’s not scalable. A service-centric approach avoids that by creating a stable foundation supporting your platform’s product evolution.
Start with a service-centric model
Everything should revolve around the Service - that’s the atomic unit of value in most engineering orgs. Services produce value, are owned by teams, consumed by customers, and backed by resources.
Define clear, non-circular relationships
Avoid circular references like Team → User → Service → Team
. This leads to brittle graph traversals and unpredictable outcomes.
Keep relationships unidirectional when possible
For example: Service → Team
(owns)
Service → Product
(belongs to)
Service → Customer
(serves)
Avoid relationships like Team ↔ Team
unless you have a solid use case (e.g., org chart).
Avoid dumping everything into the Service blueprint
Services shouldn’t carry metadata that belongs elsewhere. For example, incident history belongs in an Incident
blueprint linked to a Service
, not embedded as property inside the Service
.
Represent change over time cleanly
If something changes often (e.g., Git SHA
, build artifact
, deployment
), model it as a separate time-bound blueprint like Deployment
, Build
, or Commit
.
Blueprints (core Entity types):
Service
Team
User
Customer
Product
Relationships:
Service
→ Team
(ownership, runbook responsibility)Service
→ Product
(which product it supports)Service
→ Customer
(consumers of the service)Service
→ User
(tech leads, on-call, reviewers)Team
→ User
(members)Product
→ Customer
(buyers/users)This structure keeps services as the center, prevents circular references, and makes it easy to answer key questions like:
This diagram visually represents a service-centric data model, placing Service at the core and illustrating its relationships with Team, User, deployment, cluster, and organisation. It highlights how services act as the primary integration point between organisational units, technical ownership.
There are a number of tools you can use to implement a service-centric IDP model - Backstage, Cortex, OpsLevel, Port, and even custom-built platforms using metadata stores or graph databases. The core principles we’ve laid out here apply across the board. If your platform models services well and captures their relationships clearly, you’re in a good place.
For the sake of clarity and practicality, I’ll use Port as the example here because it provides a flexible modeling framework with blueprints and relationships that map closely to the ideas discussed above. If you’re using another tool, the same logic still applies - you’ll just translate it into the concepts and structures that your platform supports.
In Port, you define these core Entity types as blueprints, which are schema definitions that model the structure and relationships of the entities in your internal developer platform - for example, Service, Team, User, Customer, and Product will be the blueprints. For example:
Start by defining your service
blueprint. This should include properties like below, but not limited to:
Below is a definition of a service catalog and its relations.
{
"identifier": "service",
"title": "Service",
"icon": "Microservice",
"schema": {
"properties": {
"description": {
"title": "Description",
"type": "string"
},
"type": {
"title": "Type",
"type": "string",
"enum": ["Backend", "Frontend", "Library"]
},
"tier": {
"title": "Tier",
"type": "string",
"enum": ["Mission Critical", "Customer Facing", "Internal Service"]
},
"runbooks": {
"title": "Runbooks",
"type": "array",
"items": {
"type": "string",
"format": "url"
}
},
"monitor_dashboards": {
"title": "Dashboards",
"type": "array",
"items": {
"type": "string",
"format": "url"
}
},
"healthStatusinProd": {
"title": "Health Status",
"type": "string",
"enum": ["Healthy", "Degraded", "Progressing"]
}
}
},
"relations": {
"repository": {
"title": "Repository",
"target": "githubRepository",
"many": false
},
"pager_duty_service": {
"title": "On-call (PagerDuty)",
"target": "pagerdutyService",
"many": false
},
"code_owners": {
"title": "Code Owners",
"target": "github_user",
"many": true
},
"dependencies": {
"title": "Depends On",
"target": "service",
"many": true
}
}
}
The above minimal service blueprint defines the core attributes of a software service in Port, including its type, tier, health status, runbooks, and dashboards. It also maps key relationships such as linked repositories, on-call ownership via PagerDuty, code owners, and service dependencies, making it ideal for visibility, incident response, and internal developer platform use cases.
Entity inside the Service blueprint
{
"identifier": "application",
"title": "application component",
"blueprint": "service",
"properties": {
"description": "Handles user authentication and profile management.",
"type": "Backend",
"tier": "Mission Critical",
"lifecycle": "Production",
"language": "Python",
"runbooks": ["https://docs.company.com/runbooks/user-service"],
"monitor_dashboards": ["https://grafana.company.com/d/user-service"],
"syncStatusinProd": "Synced",
"healthStatusinProd": "Healthy",
"syncStatusinTest": "Synced",
"healthStatusinTest": "Healthy",
"last_push": "2025-06-01T10:12:00Z",
"locked_in_prod": false,
"locked_in_test": false
},
"relations": {
"repository": "user-service-repo",
"pager_duty_service": "pd-user-service",
"code_owners": ["alice@company.com", "bob@company.com"],
"dependencies": ["auth-service", "notification-service"],
"domain": "identity"
}
}
This JSON defines an application entity in Port using the existing service blueprint. It captures essential metadata like service type, tier, lifecycle, deployment health, code ownership, dependencies, runbooks, and dashboards. This enables centralized visibility, on-call readiness, and integration with tools like GitHub and PagerDuty.
Once your services are modeled properly, you can plug in other entities:
More importantly, Port allows you to define relationships between these entities. That’s where things get powerful - when you can answer questions like:
These aren’t abstract questions. They’re the ones your engineering and support teams ask every single day. If your IDP can’t answer them, it’s not doing its job.
Example of a service blueprint definition below
If you remember one thing from this post, let it be this:
Put service catalogs at the center. Build around reality, not abstraction.
A good IDP is like a well-designed map. It shouldn’t cover everything - just the things you need to navigate confidently. In most engineering orgs, that means knowing what services exist, who owns them, how they relate, and what value they deliver.
Model that well, and your platform becomes more than a dashboard. It becomes the connective tissue of your engineering organization. All of this will help your platform excel in this dynamic environment. If you’re looking for any help with building a platform the right way, you can also reach out to InfraCloud’s platform engineering experts, and let’s explore how InfraCloud can create a platform that truly serves your goals.
Exploring Platform Engineering? Read the other blog posts from our Platform Engineering series and browse webinars on our YouTube channel. Do share your thoughts on this article and platform engineering in general by connecting with me on LinkedIn.
Building a Platform? Download our free 22-page Platform Engineering OSS Reference Architecture eBook, which includes blueprints, frameworks, tool suggestions, maturity questionnaire, and much more!
We hate 😖 spam as much as you do! You're in a safe company.
Only delivering solid AI & cloud native content.