Production engineering guide for platform team topologies covering patterns, implementation strategies, and operational best practices.
Platform teams enable engineering organisations to scale effectively by abstracting infrastructure, tooling, and operational complexity into reusable capabilities. Platform Team Topologies defines how these teams are structured, interact, and evolve to serve product teams, ensuring consistency, velocity, and resilience across a growing engineering landscape. This model is essential when an organisation grows beyond a single team, where duplicated effort, inconsistent practices, and slow onboarding become visible and costly.
The core of Platform Team Topologies is aligning team shape with the responsibilities they own. The platform team is not a monolithic entity, but a collection of roles that collaborate through well-defined interaction patterns. The key roles are:
The structure is not static. Teams grow, responsibilities shift, and integration points evolve. The goal is to make platform services discoverable, composable, and self-service.
A shared platform contract is the foundation of a coherent platform. It defines the interface between the platform team and product teams through a combination of API contracts, configuration schemas, and operational expectations.
The contract is expressed in a platform-contract.json file, placed at the root of the platform’s public API directory:
{
"name": "event-streaming-platform",
"version": "1.2.0",
"description": "A unified event streaming service using Apache Kafka.",
"api": {
"base_url": "https://platform.example.com/api/v1",
"auth": {
"type": "bearer",
"required_scopes": ["platform:read", "platform:write"]
},
"endpoints": [
{
"path": "/topics",
"method": "POST",
"request": {
"schema": {
"type": "object",
"properties": {
"name": { "type": "string", "minLength": 3 },
"replication_factor": { "type": "integer", "minimum": 1 },
"retention_hours": { "type": "integer", "minimum": 1 }
},
"required": ["name"]
}
},
"response": {
"schema": {
"type": "object",
"properties": {
"topic_id": { "type": "string" },
"name": { "type": "string" },
"created_at": { "type": "string", "format": "date-time" }
},
"required": ["topic_id", "name"]
}
}
}
],
"configuration": {
"schema": {
"type": "object",
"properties": {
"logging": {
"type": "object",
"properties": {
"level": { "enum": ["debug", "info", "warn", "error"] },
"retention_days": { "type": "integer", "minimum": 1 }
}
},
"auto_scaling": {
"type": "object",
"properties": {
"max_instances": { "type": "integer", "minimum": 1 },
"min_instances": { "type": "integer", "minimum": 1 },
"cpu_threshold": { "type": "number", "minimum": 0.0, "maximum": 1.0 }
}
}
}
}
}
}
}
Product teams consume this contract to integrate with the platform. The contract is versioned and published to the internal developer portal, where it is discoverable via search, metadata, and usage examples.
Product teams onboarding to the platform must be able to bootstrap a new service with minimal platform team involvement. The process is orchestrated through a platform-setup.yaml file, checked into the product team’s repository:
platform:
name: "user-auth-service"
dependencies:
- [email protected]
- [email protected]
configuration:
event-streaming:
topic: "user-events"
retention_hours: 168
monitoring:
log_level: "info"
alert_threshold: 0.8
environment: "staging"
deploy:
strategy: "canary"
rollout_steps:
- "wait 30s after first instance"
- "verify health check on 90% of instances"
- "promote to production after 1 hour"
When a product team pushes this file to platform-setup.yaml, the platform’s internal CI/CD pipeline triggers a self-service provisioning workflow:
git commit -m "Add platform setup" → triggers platform-sync job.platform-sync reads the platform-setup.yaml, validates it against the platform-contract.json.configuration keys, and validates environment against a known list (staging, production, canary).environment is not recognised.kubectl apply:kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
name: user-auth-service-staging
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-auth-service
namespace: user-auth-service-staging
spec:
replicas: 3
selector:
matchLabels:
app: user-auth-service
template:
metadata:
labels:
app: user-auth-service
spec:
containers:
- name: app
image: registry.example.com/user-auth-service:latest
ports:
- containerPort: 8080
env:
- name: KAFKA_TOPIC
value: "user-events"
- name: LOG_LEVEL
value: "info"
EOF
A failure in the platform-sync job results in a detailed error message in the pull request:
ERROR: platform-setup.yaml validation failed
- Missing required key: 'monitoring.alert_threshold'
- Unknown environment: 'preprod' (expected: staging, production, canary)
- Dependency 'event-streaming-platform' version '1.2.0' not found in registry
- Invalid value for 'event-streaming.retention_hours': must be >= 1, got 0
The product team can then fix the platform-setup.yaml, re-run the sync, and receive a new platform-setup.yaml with suggested defaults.
The internal developer portal surfaces the platform’s capabilities as a catalog. Each service is described through a service.yaml file in the platform’s repository:
name: "event-streaming-platform"
version: "1.2.0"
maintainer: "[email protected]"
description: "Apache Kafka-backed event streaming service with built-in monitoring and auto-scaling."
tags:
- messaging
- streaming
- real-time
- data
categories:
- "Core Infrastructure"
- "Data & Analytics"
- "Observability"
dependencies:
- "kubernetes"
- "prometheus"
- "jaeger"
quickstart:
- "Create a topic via API"
- "Publish events using curl"
- "Subscribe with a consumer client"
examples:
- title: "Event-driven user registration"
code:
language: "python"
source: |
from kafka import KafkaProducer
producer = KafkaProducer(bootstrap_servers=['kafka.platform.example.com'])
producer.send('user-events', b'{"user_id": 123, "action": "signup"}')
producer.flush()
description: "Send a user signup event to the event stream."
This file is served via a static site generator (e.g., Hugo, Jekyll) and rendered at https://platform.example.com/catalog/event-streaming-platform.
The catalog includes:
platform-setup.yaml for the service.Platform teams must manage dependencies across services. Dependencies are declared in dependencies.yaml at the platform root:
dependencies:
- name: "event-streaming-platform"
version: "1.2.0"
source: "https://platform.example.com/api/v1/topics"
required: true
upgrade_policy:
strategy: "minor"
auto_update: true
notification: "slack"
changelog:
url: "https://platform.example.com/changelog/event-streaming-platform"
stability: "stable"
maintenance: "active"
The platform’s dependency manager runs daily, checking for:
platform-contract.json schema changes).When a dependency is updated, it triggers a change notification via curl:
curl -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer SLACK_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel": "#platform-updates",
"text": "Dependency update: event-streaming-platform v1.3.0 available",
"attachments": [
{
"title": "Breaking changes",
"text": "Added `schema_version` field to topic creation. Removed `enable_compaction`.",
"fields": [
{
"title": "Stability",
"value": "stable"
},
{
"title": "Maintenance",
"value": "active"
}
],
"actions": [
{
"type": "button",
"text": "Upgrade all services",
"url": "https://platform.example.com/upgrade/event-streaming-platform"
}
]
}
]
}'
Product teams can subscribe to dependency updates via email or Slack. They receive a platform-upgrade job in their CI/CD pipeline, which:
platform-setup.yaml.Platform services are monitored via a standardised set of metrics, logs, and traces. The platform team defines a platform-observability.json file:
{
"metrics": [
{
"name": "platform.service.latency",
"description": "Average latency of platform service calls",
"unit": "milliseconds",
"query": "rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m])",
"alert": {
"threshold": 200,
"severity": "warning",
"duration": "10m"
}
},
{
"name": "platform.dependency.availability",
"description": "Availability of critical dependencies",
"unit": "percent",
"query": "avg by (dependency) (1 - rate(dependency_failure_count[5m])) * 100",
"alert": {
"threshold": 95,
"severity": "critical",
"duration": "15m"
}
}
],
"logs": {
"source": "platform",
"fields": ["service", "operation", "trace_id", "level", "message"],
"query": "source=platform and level=error"
},
"traces": {
"format": "open-telemetry",
"exporter": "jaeger",
"sampling": 0.1
}
}
This configuration is applied via prometheus.yml and jaeger-config.yaml across all platform services.
When a service fails, the platform logs a trace with a trace_id and a platform.failure event:
{
"trace_id": "a1b2c3d4e5f6",
"service": "event-streaming-platform",
"operation": "create-topic",
"error": {
"code": "TOPIC_CREATION_FAILED",
"message": "Kafka returned error: Topic already exists",
"details": {
"kafka_error_code": 10,
"topic_name": "user-events"
}
},
"timestamp": "2025-04-05T14:23:11.000Z"
}
The platform team receives alerts in Grafana and logs in Loki. Product teams can correlate their service traces with the platform’s traces via trace_id, enabling end-to-end visibility.
The platform evolves through a guild model. Guilds meet bi-weekly to discuss:
Feedback is collected via a feedback.yaml file in the platform’s repository:
feedback:
- id: "fb-2025-04-01"
submitted_by: "[email protected]"
service: "event-streaming-platform"
type: "feature_request"
title: "Support schema registry integration"
description: "Allow producers to register schemas and validate events."
priority: "high"
votes: 14
comments:
- author: "[email protected]"
text: "This is crucial for data teams. Consider adding schema versioning."
timestamp: "2025-04-02T10:15:00Z"
Guilds vote on feature proposals, and the platform team implements them. The change is documented in platform-changelog.json:
[
{
"version": "1.3.0",
"date": "2025-04-05",
"changes": [
{
"type": "feature",
"title": "Schema registry integration",
"description": "Producers can register and validate event schemas."
},
{
"type": "bugfix",
"title": "Topic creation fails with existing topic",
"description": "Fixed Kafka error handling for duplicate topic creation."
}
]
}
]
This process ensures that the platform evolves not just from internal needs, but from real usage and feedback.
This page was rewritten on 18 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy