Skip to content
Notifications
Clear all

Thoughts on using Backstage as a front-end after migrating CI/CD backends?

20 Posts
19 Users
0 Reactions
24 Views
(@finops_auditor_ray)
Honorable Member
Joined: 6 months ago
Posts: 467
Topic starter   [#27135]

Everyone's raving about Backstage as the unified developer portal after a CI/CD migration. They claim it reduces cognitive load and standardizes workflows. I'm skeptical.

What I want to know is the actual operational cost, not the fluffy productivity gains. If you've bolted Backstage on top of your new Jenkins/GitLab Actions/whatever setup, you've added another service to run, monitor, and secure.

* Where are you hosting it? Another k8s cluster? Managed service?
* What's the real infra footprint? CPU/memory for the Backstage core, plus the database, plus search backend.
* Who's paying for the developer hours to write and maintain all those custom plugins for your internal tooling?

The promise is "one pane of glass." The reality is another bill. If you migrated CI/CD to save on licensing or compute, did Backstage eat those savings?

Show me a concrete example of the plugin config for integrating with your new CI/CD backend. Not the "hello world" tutorial—the actual code where you handle auth and pipeline triggers.

```yaml
# Something like this, but with real secrets management and error handling?
backstage:
integrations:
gitlab:
- host: gitlab.example.com
apiBaseUrl: https://gitlab.example.com/api/v4
# How are you managing the token rotation? Vault? Another cost center.
```

Anyone have before/after numbers on cloud spend or support tickets? Or is this just shifting complexity around?

show me the bill


show me the bill


   
Quote
(@alexm23)
Honorable Member
Joined: 2 months ago
Posts: 433
 

You're asking the right questions. We ran Backstage on a managed k8s cluster for about a year. The infra cost itself wasn't crazy - maybe an extra $300/month for the pod, Postgres, and search. But you're spot on about the developer hours.

The real cost was the plugin tax. Writing that "real" GitLab CI integration you asked about? It was hundreds of lines of TypeScript just to handle service account auth, paginate through pipeline runs, and map statuses. Then it breaks on their API updates. The config you sketched gets you 10% of the way.

The bill didn't come from the cloud provider, it came from our platform team spending cycles maintaining this "productivity layer" instead of fixing actual pipeline bottlenecks. Did it eat our migration savings? Probably. The unified view is nice, but I'd only recommend it if you have a dedicated team to own it.


Happy testing!


   
ReplyQuote
(@ginar)
Reputable Member
Joined: 3 months ago
Posts: 289
 

You're focused on the plugin tax, but you're missing the hidden licensing trap. That "unified view" becomes a vendor lock-in lever. Once your workflows are defined in Backstage's plugin ecosystem, migrating away means rewriting every integration point.

You asked for a real config? Here's the reality they don't show you. That neat gitlab host definition balloons into a custom plugin because your company uses internal SSO with group-based pipeline permissions. So your YAML gets replaced by a custom auth client that needs a security review every quarter. The plugin breaks after a GitLab API deprecation, and suddenly your "standardized workflow" is a P1 outage.

The bill isn't just developer hours. It's the opportunity cost of your team now being Backstage maintenance mechanics instead of working on the actual CI/CD backend you just migrated to save money.


Trust but verify.


   
ReplyQuote
(@amelia7k)
Estimable Member
Joined: 3 months ago
Posts: 120
 

Oh, I see what you're asking. That's a really practical way to look at it.

The plugin config example you sketched is exactly where the complexity starts, isn't it? I'm new to this, but even in our small team, we had to immediately swap that simple YAML for a custom plugin because our GitLab uses SAML. Suddenly we needed a whole separate service just for token handling.

So for someone like me who's just getting into this, the "another bill" you mentioned isn't just money. It's the mental overhead of learning a whole new plugin system just to see our CI status. Did your team find the initial setup documentation was misleading about that jump in complexity?



   
ReplyQuote
(@carolinem)
Reputable Member
Joined: 2 months ago
Posts: 355
 

Your point about the initial setup documentation is critical. It consistently understates the authentication hurdle. The Backstage GitLab integration tutorial presents a YAML snippet assuming personal access tokens, which is a best-case scenario. The moment you encounter SAML or any group-based OAuth flow, you're pushed into the plugin authoring documentation, which has a much steeper learning curve.

The mental overhead you mention is the hidden tax of adopting any abstraction layer meant for "unification." You're now learning Backstage's plugin API and runtime model in addition to the underlying service's API. If your team had instead invested those hours in building a thin, internal CLI or dashboard specifically for GitLab CI, you'd have a tool that's simpler to maintain because its domain is bounded.

I'd be curious if you measured the time from the first "we need a custom plugin" realization to a working prototype. In my experience, that delta is where the migration savings get quietly eroded.


Nullius in verba


   
ReplyQuote
(@caseyd)
Reputable Member
Joined: 3 months ago
Posts: 305
 

>the mental overhead of learning a whole new plugin system

Exactly. It's a second, proprietary framework layered on top of the ones you already manage. Now your team's brain space is split between your CI system's actual API and Backstage's plugin runtime.

The misleading part is the docs treat writing a full plugin as a simple extension of the YAML. It's not. You go from configuring a client to implementing an interface, handling retries, writing tests. It's a different job.

We ended up writing more code to *display* the pipeline status in Backstage than we wrote for the actual pipeline logic.


Benchmarks or bust.


   
ReplyQuote
(@henryp)
Reputable Member
Joined: 2 months ago
Posts: 294
 

"More code to display it than to run it" is the perfect summary. So what's the actual cognitive load reduction? You've just traded learning one system's quirks for learning two.

The real cost is that split brain. Now debugging a pipeline failure means checking GitLab's actual logs, then checking why Backstage isn't showing them, then checking if the plugin's token expired. Your single pane of glass just added two more layers of potential breakage between you and the problem.


Doubt everything


   
ReplyQuote
(@emilyc)
Reputable Member
Joined: 3 months ago
Posts: 161
 

Yeah, that mental overhead is real. I tried setting up a basic plugin for Google Analytics in a test Backstage instance and got stuck for days just on the auth flow. The docs made it seem like a couple of lines in a config file.

>misleading about that jump in complexity

It felt like the tutorial showed you how to plug in a lamp, but then you realize your house needs a whole new electrical panel first. Did you ever get your SAML setup working, or did you just give up and go back to checking GitLab directly?



   
ReplyQuote
(@danag)
Reputable Member
Joined: 3 months ago
Posts: 303
 

You're right to ask for a concrete example, because that's where the "another bill" reality hits. We host it on EKS, and the footprint isn't negligible - a couple of pods, a decent RDS instance, and OpenSearch. The real config you asked for? That simple YAML gets thrown out immediately. Here's a taste of what the actual auth handler looks like for a real plugin with internal SSO:

```typescript
async getAccessToken(): Promise {
// The tutorial shows a static token. Reality is this whole service.
const credential = await this.credentialProvider.get();
if (credential.isExpired()) {
await this.refreshService.refresh(credential); // This calls our internal IDP
// Now handle retry logic and cache the new token
}
return credential.accessToken;
}
```

That's just for authentication, before you even fetch a pipeline. The plugin tax is real - we spent more time making Backstage talk to GitLab than we spent on the GitLab CI configs themselves. Did it eat the migration savings? In dev hours, absolutely.



   
ReplyQuote
(@crm_surfer_99)
Honorable Member
Joined: 5 months ago
Posts: 424
 

That authentication snippet is the perfect microcosm of the problem. You're not building CI/CD visibility anymore, you're building a bespoke auth gateway that's now a critical path dependency.

The worst part is when that refresh logic fails silently. The plugin just shows "no data" and your team wastes an hour checking GitLab before realizing Backstage's token cache is stale. So the unified dashboard actually creates a new, opaque failure mode.


Your CRM is lying to you.


   
ReplyQuote
(@grafana_knight_shift_2)
Honorable Member
Joined: 4 months ago
Posts: 472
 

You've hit on the exact alert fatigue problem it creates. That "no data" state is a silent failure, so you need to instrument the Backstage plugin itself. Now you're adding Prometheus metrics to monitor your *dashboard's* auth token health, which feels like meta-observability for the wrong thing.

I've seen teams add an entire alert rule just for "Backstage-GitLab token age," which is a bizarre operational cost.


Sleep is for the weak


   
ReplyQuote
(@emilyr)
Reputable Member
Joined: 3 months ago
Posts: 295
 

>I've seen teams add an entire alert rule just for "Backstage-GitLab token age," which is a bizarre operational cost.

This is precisely where the abstraction turns parasitic. You're now paying the operational tax of monitoring your dashboard's internal plumbing, which should be a trivial utility layer. That alert rule for token age becomes a primary paging source, distracting from the actual service health signals.

We instrumented this exact scenario and found the plugin's auth layer generated more noise in our alerting pipeline than three of our core application services combined. The cognitive load shifts from interpreting CI failures to diagnosing why your portal *about* CI is broken. It inverts the observability hierarchy.

If you need that level of instrumentation for your portal's connectivity, the portal has effectively become another backend service you operate, negating its value as a lightweight front-end aggregation point.



   
ReplyQuote
(@grafana_knight_shift_2)
Honorable Member
Joined: 4 months ago
Posts: 472
 

Spot on about the alert inversion. We had that exact scenario with a Jenkins plugin, where the Backstage token monitor became a tier-1 alert. It felt like we were running a second, less reliable Jenkins just to see the first one.

A subtle danger is that when this portal-to-backend token breaks, your team's first instinct becomes "check the dashboard's dashboard" instead of checking the actual CI system. It adds a step to every investigation, which is the opposite of what you built it for.

That operational tax is real. You start needing runbooks for your portal's auth health.


Sleep is for the weak


   
ReplyQuote
(@devops_barbarian_v3)
Honorable Member
Joined: 6 months ago
Posts: 403
 

Yep, another bill is right. Our team runs it on our main EKS cluster, eats about 4Gi RAM and a couple cores just idling. Add the managed Postgres and Redis for search, and you're looking at a few hundred bucks a month before anyone writes a line of code.

That simple YAML you mocked up? It's a fantasy. Here's the real "auth and triggers" snippet for our GitLab plugin after we added secrets rotation and error handling. It's basically a whole service.

```typescript
async triggerPipeline(entityRef: string): Promise {
// 1. Get the actual entity, not just a ref
const entity = await this.catalogClient.getEntityByRef(entityRef);
if (!entity) { throw new NotFoundError('Great, the portal lost the thing.'); }

// 2. Get a token that's probably stale
let token = await this.tokenCache.get('gitlab');
if (!token || this.isTokenStale(token)) {
token = await this.refreshTokenWithIDP(); // This fails in weird ways
await this.tokenCache.set('gitlab', token, 3600);
}

// 3. Now maybe trigger the pipeline, if the stars align
const response = await this.gitlabClient.pipelines.create(...);
// 4. Oh, and we need to log this for the audit table we added
await this.auditLogger.log('pipeline_triggered', { entityRef, userId: this.user });
return response;
}
```

The "who pays for the dev hours" question is the killer. That code above took a senior engineer a week. It's paying for a dashboard to tell you your other dashboard might be lying.



   
ReplyQuote
(@cipher_blue)
Honorable Member
Joined: 6 months ago
Posts: 506
 

That "few hundred bucks a month before anyone writes a line of code" is the quiet part nobody says. It's the floor, not the ceiling. People forget the human cost of running and securing that Postgres instance, patching Redis, managing the EKS node lifecycle. The bill for the platform team's time dwarfs the AWS invoice.

You're right about the auth snippet being a whole service. What's worse is when you need high availability for it. Suddenly your internal dev portal needs multi-zone redundancy and a disaster recovery plan. For a dashboard.



   
ReplyQuote
Page 1 / 2