AI Code Generation: Bolt.new and Copilot Free

Published: Jan 21, 2025 by Isaac Johnson

We’ve spoken about v0 and Lovable.dev, but today we’ll check out another big player in the space, Bolt.new. We’ll pair this with the new Free tier of Copilot (and Gemini Code Assist). After getting something working, we’ll also leverage Midjourney to build out so of our apps image before exposing it on a proper URL with TLS hosted in Kubernetes.

Signup

We can sign up with a Github account or just email

/content/images/2025/01/boltnew-02.png

By default, we are in a Personal Plan

/content/images/2025/01/boltnew-01.png

Pricing

As I mentioned in our writeup about Lovable.dev, its pricing is all about the Tokens

/content/images/2025/01/boltnew-03.png

The ‘Free’ (Personal) plan gives us a generous 1M tokens which, so far, has met my basic needs.

Usage

We’ve done a lot of Resume apps lately so let’s do something a bit different. As it’s the new year, I’ve been doing a lot more workouts and I noticed with the LLMs, they are pretty good at building out fitness plans.

Let’s give Bolt.new a try in building an app we can use for various two-week plans

Create a fitness app with a landing page that offers 4 kinds of workout plans: cardio, strength, flexibility and endurance. When selecting one of the four we should ask for a level of 0 to 5 where 0 is “just starting” and 5 is “extreme”. We will use this selection along with the workout plan to then present a page showing a two-week workout cycle. For each day (1-14), present a page of a workout that would meet those criteria (type, level and a randomized workout plan). Include pictures if able. Make this site mobile friendly.

It looked like it might work, but preview didn’t work and the deploy seemed to time out - I left it paused for 15m before stopping at the end

Let me try and download

/content/images/2025/01/boltnew-05.png

I did an npm install and npm run dev but it’s just a blank app at this point

/content/images/2025/01/boltnew-06.png

It does not appear to me it built any app other than the boilerplate framework

/content/images/2025/01/boltnew-07.png

The thing is that in Bolt.new I can see a defined app.tsx so this download does not actually match the Web UI

/content/images/2025/01/boltnew-08.png

I left Bolt and came back in and the App.tsx seems to sadly have reset

/content/images/2025/01/boltnew-09.png

The preview works and matches what I saw locally.

reducing

I’m going to try again, but simplify my prompt to just the initial selection for now

Create a fitness app with a landing page that offers 4 kinds of workout plans: cardio, strength, flexibility and endurance. When selecting one of the four we should ask for a level of 0 to 5 where 0 is “just starting” and 5 is “extreme”. Keep the style modern and use fitness images where able.

I can see it built an app

/content/images/2025/01/boltnew-10.png

But despite what it says, there is no preview

/content/images/2025/01/boltnew-11.png

I’ll try deploy again.. but still times out.

Trying locally it did show something different - an error

/content/images/2025/01/boltnew-12.png

One issue I corrected was a lack of a “Yoga” icon from lucide.

builder@DESKTOP-QADGF36:/mnt/c/Users/isaac/Downloads/project-bolt-sb1-3u2gayjm/project$ npm run build

> vite-react-typescript-starter@0.0.0 build
> vite build

vite v5.4.8 building for production...
✓ 1470 modules transformed.
x Build failed in 31.85s
error during build:
src/App.tsx (5:2): "Yoga" is not exported by "node_modules/lucide-react/dist/esm/lucide-react.js", imported by "src/App.tsx".
file: /mnt/c/Users/isaac/Downloads/project-bolt-sb1-3u2gayjm/project/src/App.tsx:5:2

3:   Heart, 
4:   Dumbbell, 
5:   Yoga, 
     ^
6:   Timer,
7:   ChevronLeft,
...

I went to the Lucide library and replaced “Yoga” with “tangent” which seemed similar.

That’s now looking much better

/content/images/2025/01/boltnew-13.png

I went back and made the corrections in Bolt after refreshing (to stop the broken build). This was namely:

  • comment out the trailing “export”
  • set the App to have a “default export”
  • replace the “Yoga” icon with “Tangent”

Then I did a “deploy” and saw a resulting preview page

/content/images/2025/01/boltnew-14.png

I’ll now ask to build out just strength training.

/content/images/2025/01/boltnew-15.png

This is not a bad workout. We can see it has a decent 7-day plan and while it did put in some good fitness images, they don’t actually match the workout step. They are pretty darn close though and for a free image, I think it’s a good start.

I’ll now politely ask it to do the same for Cardio

That looks great, thank you. Please do the same for the cardio page.

It gave an error but also prompted me to let it fix the error.

/content/images/2025/01/boltnew-17.png

Not perfect, but not too shabby.

/content/images/2025/01/boltnew-18.png

I’ll keep going:

Fantastic. Please do the same for the Flexibility section which should create a workout with stretches and yoga with a focus on mobility.

Ahh! They got me.

/content/images/2025/01/boltnew-19.png

That said, I can download and see what we can do from there.

Since I plan to proceed with VS Code in WSL, I’ll move it into my Linux filesystem

builder@DESKTOP-QADGF36:~/Workspaces$ mv /mnt/c/Users/isaac/Downloads/project-bolt-sb1-3u2gayjm_new/project ./BoltFitnessApp
builder@DESKTOP-QADGF36:~/Workspaces$
builder@DESKTOP-QADGF36:~/Workspaces$ cd BoltFitnessApp/
builder@DESKTOP-QADGF36:~/Workspaces/BoltFitnessApp$ ls
dist              index.html         package.json       src                 tsconfig.app.json  tsconfig.node.json
eslint.config.js  package-lock.json  postcss.config.js  tailwind.config.js  tsconfig.json      vite.config.ts

Next, I’ll create a repo in Github and since I really want this Open-Source, I’ll make it public

/content/images/2025/01/boltnew-20.png

I can then push it up to Github

builder@DESKTOP-QADGF36:~/Workspaces/BoltFitnessApp$ git init
Initialized empty Git repository in /home/builder/Workspaces/BoltFitnessApp/.git/
builder@DESKTOP-QADGF36:~/Workspaces/BoltFitnessApp$ git add *.*
builder@DESKTOP-QADGF36:~/Workspaces/BoltFitnessApp$ git add src
builder@DESKTOP-QADGF36:~/Workspaces/BoltFitnessApp$ git commit -m "First"
[master (root-commit) 866e3f1] First
 14 files changed, 4856 insertions(+)
 create mode 100755 eslint.config.js
 create mode 100755 index.html
 create mode 100755 package-lock.json
 create mode 100755 package.json
 create mode 100755 postcss.config.js
 create mode 100755 src/App.tsx
 create mode 100755 src/index.css
 create mode 100755 src/main.tsx
 create mode 100755 src/vite-env.d.ts
 create mode 100755 tailwind.config.js
 create mode 100755 tsconfig.app.json
 create mode 100755 tsconfig.json
 create mode 100755 tsconfig.node.json
 create mode 100755 vite.config.ts
builder@DESKTOP-QADGF36:~/Workspaces/BoltFitnessApp$ git branch -M main
builder@DESKTOP-QADGF36:~/Workspaces/BoltFitnessApp$ git remote add origin https://github.com/idjohnson/BoltFitnessApp.git

builder@DESKTOP-QADGF36:~/Workspaces/BoltFitnessApp$ git push -u origin main
Enumerating objects: 17, done.
Counting objects: 100% (17/17), done.
Delta compression using up to 16 threads
Compressing objects: 100% (16/16), done.
Writing objects: 100% (17/17), 40.31 KiB | 10.08 MiB/s, done.
Total 17 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), done.
To https://github.com/idjohnson/BoltFitnessApp.git
 * [new branch]      main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.

I like using VSCode Locally, but one of my new favourite things to use with Github is Codespaces.

I’ll show you how that works while also showing how to add in Copilot to Codespaces

I’ll now ask Copilot via Codespaces what I would have asked Bolt - please add the next section:

App.tsx has defined a workoutPlan for cardio (getCardioPlan) and strength (getStrengthPlan). Please add one for flexibility similar to the ones mentioned.

/content/images/2025/01/boltnew-22.png

It kind of worked, but not as I had hoped

/content/images/2025/01/boltnew-23.png

I asked it again

Can you try again? I want all the same features including getting a level and using it as a multiplier and returning an week of workouts starting with Monday

This did better but I will still have to massage it a bit more

/content/images/2025/01/boltnew-24.png

I tried to nudge it a bit more:

Please pay attention to the Exercise interface at line 19. The return should be a collection of 7 WorkoutDay instances, one for each day of the week (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday). Each Workoutday then creates a collection of Exercises

This time I at least have something with which I can work:

/content/images/2025/01/boltnew-25.png

I knew there were missing fields so I tried to highlight the block and say “fix”. This did a good job of adding in all the missing fields, but didn’t handle the formatting

/content/images/2025/01/boltnew-26.png

I then took about 20 minutes to fix the formatting slowly (just adding new lines) then going through and fixing the durations to use a proper function like cardio did. I also went to Unsplash to look up some free images that are close the defined stretches

/content/images/2025/01/boltnew-27.png

I made sure to save my work

no changes added to commit (use "git add" and/or "git commit -a")
@idjohnson ➜ /workspaces/BoltFitnessApp (main) $ git add src/App.tsx 
@idjohnson ➜ /workspaces/BoltFitnessApp (main) $ git commit -m "updates"
[main a514efe] updates
 1 file changed, 150 insertions(+), 29 deletions(-)
@idjohnson ➜ /workspaces/BoltFitnessApp (main) $ 

I had a few fixes yet to do, but once I could compile, I used ‘npm run preview’ to fire up a server and Codespaces the prompted me to a URL to view the app

/content/images/2025/01/boltnew-28.png

As you can see it mostly works, but the durations are not showing

I fixed the issue with the duration and then added a rest image

/content/images/2025/01/boltnew-30.png

I’ll then just stash the changes for the moment

no changes added to commit (use "git add" and/or "git commit -a")
@idjohnson ➜ /workspaces/BoltFitnessApp (main) $ git add src/App.tsx 
@idjohnson ➜ /workspaces/BoltFitnessApp (main) $ git commit -m "fix"
[main 24ad588] fix
 1 file changed, 81 insertions(+), 20 deletions(-)
@idjohnson ➜ /workspaces/BoltFitnessApp (main) $ git push
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 2 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (8/8), 1.52 KiB | 1.52 MiB/s, done.
Total 8 (delta 4), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (4/4), completed with 2 local objects.
To https://github.com/idjohnson/BoltFitnessApp
   866e3f1..24ad588  main -> main

I came back later and brought down the code locally to keep going.

I decided this time to ask Gemini Code Assist on how I might fix the images to not reference external URLs

/content/images/2025/01/boltnew-31.png

I then asked Gemini and Copilot at the same time to help me gather the images. Gemini took longer but did deliver me the full list so it was more complete

/content/images/2025/01/boltnew-32.png

I changed just the first, the bench press (though I downloaded all the images) and it worked great

/content/images/2025/01/boltnew-33.png

This was way faster in loading, and for the new images it worked great

/content/images/2025/01/boltnew-34.png

But the automated ones had some broken images and some that just didn’t make a whole lot of sense. For instance, cycling was just a picture of space

/content/images/2025/01/boltnew-35.png

Midjourney

I now want to replace these pretty images with some Isometric generated art.

I tried a few options, but settled on, for instance

modern illustration of a deadlift exercise, isometric with white background

/content/images/2025/01/boltnew-36.png

In testing, I found the images appear a bit cropped

/content/images/2025/01/boltnew-37.png

I spent several hours using MidJourney to build out some decent images. Here is just a snippet of me trying to build one isometric exercise

Dockerfile

I next asked Copilot to help build out a Dockerfile. It actually refused to help me if I included the package.json but it would work just fine when I removed it

/content/images/2025/01/boltnew-39.png

But I could not get that to work. So I then tried Gemini Code Assist which seemed to have a better idea

/content/images/2025/01/boltnew-40.png

It wasn’t perfect, but not far off. I fixed it by commenting out the ci step and naming the builder container

FROM node:20-alpine AS builder

WORKDIR /app

COPY package.json package-lock.json ./

#RUN npm ci --omit=dev

COPY . .

RUN npm run build

FROM node:20-alpine

WORKDIR /app

COPY --from=builder /app/dist ./dist

COPY package.json package-lock.json ./

#RUN npm ci --omit=dev --production

EXPOSE 5173

CMD ["npx", "vite", "preview", "--port", "5173", "--host"]

Which ran locally without issue

/content/images/2025/01/boltnew-41.png

Let’s see if we can get Copilot to build out a Github workflow

/content/images/2025/01/boltnew-42.png

I put it in the folder it would need to be in, namely .github/workflows

/content/images/2025/01/boltnew-43.png

name: Build and Push Docker Image

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: $
          password: $

      - name: Build and push Docker image
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: ghcr.io/$/boltfitnessapp:latest

While it did build, the error shows us that we need a proper GH Token for logging in

/content/images/2025/01/boltnew-44.png

That was just due to a missing permission on the workflow file

/content/images/2025/01/boltnew-45.png

which worked

/content/images/2025/01/boltnew-46.png

Now we have an image at

ghcr.io/idjohnson/boltfitnessapp:latest

I’ll now ask Copilot to create the Kubernetes manifest

create a kubernetes manifest that creates a deployment with the image ghcr.io/idjohnson/boltfitnessapp:latest. it should always pull a fresh image. It should expose port 5173 and have 2 replicas. The manifest should also include a service to expose the deployment that is of type clusterip

/content/images/2025/01/boltnew-47.png

Let’s now try to deploy to k8s

$ kubectl apply -f manifest.yaml
deployment.apps/boltfitnessapp-deployment created
service/boltfitnessapp-service created

A quick port-forward works

builder@LuiGi:~/Workspaces/BoltFitnessApp$ kubectl get svc boltfitnessapp-service
NAME                     TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
boltfitnessapp-service   ClusterIP   10.43.116.26   <none>        5173/TCP   79s
builder@LuiGi:~/Workspaces/BoltFitnessApp$ kubectl port-forward svc/boltfitnessapp-service 5173:5173
Forwarding from 127.0.0.1:5173 -> 5173
Forwarding from [::1]:5173 -> 5173
Handling connection for 5173
Handling connection for 5173
Handling connection for 5173

So let’s finish this phase with a proper ingress. I’ll create an A Record

$ gcloud dns --project=myanthosproject2 record-sets create boltfit.steeped.spac
e --zone="steepedspace" --type="A" --ttl="300" --rrdatas="75.73.224.240"
NAME                    TYPE  TTL  DATA
boltfit.steeped.space.  A     300  75.73.224.240

So I then went to use it

builder@LuiGi:~/Workspaces/BoltFitnessApp$ cat ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: gcpleprod2
    ingress.kubernetes.io/proxy-body-size: "0"
    ingress.kubernetes.io/ssl-redirect: "true"
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.org/client-max-body-size: "0"
    nginx.org/proxy-connect-timeout: "3600"
    nginx.org/proxy-read-timeout: "3600"
    nginx.org/websocket-services: boltfitnessapp-service
  name: boltfitnessapp
spec:
  rules:
  - host: boltfit.steeped.space
    http:
      paths:
      - backend:
          service:
            name: boltfitnessapp-service
            port:
              number: 5173
        path: /
        pathType: ImplementationSpecific
  tls:
  - hosts:
    - boltfit.steeped.space
    secretName: boltfitnessapp-tls
builder@LuiGi:~/Workspaces/BoltFitnessApp$ kubectl apply -f ./ingress.yaml
ingress.networking.k8s.io/boltfitnessapp created

So then I can apply it

$ kubectl get cert boltfitnessapp-tls
NAME                 READY   SECRET               AGE
boltfitnessapp-tls   True    boltfitnessapp-tls   78s

Which now has a functioning app exposed via TLS

/content/images/2025/01/boltnew-48.png

Summary

Today we used Bolt.new to create a brand-new fitness app and took it as far as the free tier allowed us. I then used the new Free tier of Copilot to help build out more of the app along with Gemini Code Assist. We tied in Midjourney for image generation and wrapped by, again, using Copilot to help build out a Kubernetes manifest.

I would likely look to a better way to do images and the Midjourney approach did take plenty of time. I also would want to use something to build GIF images or some form of animations next. I also left the Endurance Training empty for a second pass later.

Overall, this was none too hard, but there were some challenges that required manual intervention and code corrections.

The app itself is totally Open-Source, so if you desire to expand it or fork it, by all means take and use. The repository is here:

https://github.com/idjohnson/BoltFitnessApp.git

OpenSource Bolt AI Docker Copilot Kubernetes

Have something to add? Feedback? You can use the feedback form

Isaac Johnson

Isaac Johnson

Cloud Solutions Architect

Isaac is a CSA and DevOps engineer who focuses on cloud migrations and devops processes. He also is a dad to three wonderful daughters (hence the references to Princess King sprinkled throughout the blog).

Theme built by C.S. Rhymes