How to Set Up Backstage On K8s with Helm - part 1, set up for success

I recently set up on our cluster. It wasn’t super-easy, so I decided to “go deep” and tried to make this a learning opportiunity.

I’m also definitely not a DevOps expert, so I had to learn some stuff myself along the way. Here’s my best approximation at a useful guide for anyone who’s going to walk the same path! Hopefully I can save you some time.

Backstage logo

Part 1

In this part we’re going to:

  1. Set up our repository
  2. Build a docker image
  3. Install Backstage on a cluster
  4. Test our dev-deploy-test loop

What you’ll need?

All the backstage prerequisites, and…

  • A working K8s cluster (minikube start should be good enough if you’re just learning)
  • kubectl || K9s || Lens
  • helm
  • A GitHub project with some software components you want to track

And some patience, cause this ain’t gonna be a smooth ride…

First thing first - get the code and store it in a repository

This might be surprising - aren’t we going to just helm install this?

So, no. To get anything done with Backstage beyond hello world, you need to mess around with the actual source code. So you’re going to want a repo of your own; otherwise, you won’t be able to track changes which we’ll do later (like adding authentication to the app).

Install the latest node LTS by running:

nvm install 16
nvm use 16

BTW: I opened a PR for the Backstage team to include a .nvmrc file, so you should be able to just run nvm use next time. :) Track it here:

GitHub Pull request link.

If you have multiple Node versions running on your machine remember to do this for each shell session you open.

Then run:

npx @backstage/create-app

Choose a name, let it run yarn install, moan internally about modern package management and install times while it runs.

Then to test it you can cd into your new app and run yarn dev. You ought to see something like this:


Now, since we’re going to need to perform many changes, most of them on the codebase, now’s a good time to get the code into a repository. So open a GitHub repo, and run the following:

# if you haven't already, git config --global init.defaultBranch main
git init
git add .
git commit -sv
git remote add origin <your repo here>
git push -u origin main
git checkout -b dev

Building a docker image and pushing to a repository

Now that we have the code set up, we need to build an image and push it to a repository our cluster can use. In this example I’ll be using AWS ECR. Once the repository has been created, here’s your magic one-liner:

yarn install --frozen-lockfile && 
    yarn build && 
    docker buildx build . -f packages/backend/Dockerfile --tag my-backstage --platform linux/amd64 && docker tag my-backstage:latest <ECR_URL_HERE> && 
    docker push <ECR_URL_HERE>

Setting up the application on K8s using helm

Grab the chart

We’re going to use this helm chart. According to helm best practices, we should pull the chart and inspect it, not just install it without reading! Thanks for the tip twxrob).


helm repo add backstage
helm pull --untar backstage/backstage

Install, and make sure it works

Now is a good time to make sure the image works OK in the cluster. You need to update the image in the values.yaml file:

    -    registry: ""
    -    repository: ""
    -    tag: ""
    +    registry: ''
    +    repository: <ECR_URL_HERE>
    +    tag: latest


helm install -f values.yaml my-backstage-release .

And test by port-forwarding the app to your local machine. You’re going to need to port forward port 3000 and port 7007.


It should look like this:


Run the dev-deploy-test loop

So, we have everything we need to start messing around with changes. But now is the best time to stop and make sure it all operates smoothly. So let’s make a very small change, and see what the dev-deploy-test loop looks like for us.

Let’s change the title of the application:

❯ gd
diff --git a/app-config.yaml b/app-config.yaml
index 4a058de..0feb730 100644
--- a/app-config.yaml
+++ b/app-config.yaml
@@ -1,5 +1,5 @@
 -  title: Scaffolded Backstage App
 +  title: My Backstage App
    baseUrl: http://localhost:3000

Then re-run the magic oneliner from before (the one that starts with yarn) to rebuild the docker and push it.

Finally, restart your deployment:

❯ k rollout restart deployment/reco-backstage-release
deployment.apps/reco-backstage-release restarted

Click on search, and make sure the change actually worked!



Now we need to start configuring Backstage to make it useful - set up authentication, GitHub integration, and more.

The first thing you really ought to do is to make the service accessible via DNS from outside the cluster - otherwise, you’ll have to redo the port forward each time, and that’s not a pleasent experience at all. So get on that, first!

Will there be a part 2?

Probably not. Most of the config I did after setting up this Helm is too specific to my org (, so I assume it won’t really be useful for you. My DMs are open - if anyone will ask, I’ll write the second part up :)