I'm trying to deploy an Angular app to GitHub Pages. I'm using Angular 19 and Node 22. I've been days on it but due to different versions and tutorials I'm quite confused on how to deploy my app and keep getting a 404 error. The way I'm trying to deploy it is by building the docs folder with npm run build command and pushing it GitHub master branch. This is my configuration on GitHub Pages: And here my related files: // package.json { "name": "bible-quiz", "version": "0.0.0", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build --configuration=production --output-path docs --base-href /bible-quiz/ && mv docs/browser/* docs/ && rmdir docs/browser", "watch": "ng build --watch --configuration development", "test": "ng test" }, "private": true, "dependencies": { "@angular/animations": "^19.1.0", "@angular/common": "^19.1.0", "@angular/compiler": "^19.1.0", "@angular/core": "^19.1.0", "@angular/forms": "^19.1.0", "@angular/platform-browser": "^19.1.0", "@angular/platform-browser-dynamic": "^19.1.0", "@angular/router": "^19.1.0", "@tailwindcss/postcss": "^4.0.0", "postcss": "^8.5.1", "rxjs": "~7.8.0", "tailwindcss": "^4.0.0", "tslib": "^2.3.0", "zone.js": "~0.15.0" }, "devDependencies": { "@angular-devkit/build-angular": "^19.1.4", "@angular/cli": "^19.1.4", "@angular/compiler-cli": "^19.1.0", "@types/jasmine": "~5.1.0", "jasmine-core": "~5.5.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.0", "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.1.0", "typescript": "~5.7.2" } } // angular.json { "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "bible-quiz": { "projectType": "application", "schematics": {}, "root": "", "sourceRoot": "src", "prefix": "app", "architect": { "build": { "builder": "@angular-devkit/build-angular:application", "options": { "outputPath": "docs", "index": "src/index.html", "browser": "src/main.ts", "polyfills": [ "zone.js" ], "tsConfig": "tsconfig.app.json", "assets": [ { "glob": "**/*", "input": "public", "output": "/" } ], "styles": [ "src/styles.css" ], "scripts": [] }, "configurations": { "production": { "budgets": [ { "type": "initial", "maximumWarning": "500kB", "maximumError": "1MB" }, { "type": "anyComponentStyle", "maximumWarning": "4kB", "maximumError": "8kB" } ], "outputHashing": "all" }, "development": { "optimization": false, "extractLicenses": false, "sourceMap": true } }, "defaultConfiguration": "production" }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "configurations": { "production": { "buildTarget": "bible-quiz:buildroduction" }, "development": { "buildTarget": "bible-quiz:build:development" } }, "defaultConfiguration": "development" }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n" }, "test": { "builder": "@angular-devkit/build-angular:karma", "options": { "polyfills": [ "zone.js", "zone.js/testing" ], "tsConfig": "tsconfig.spec.json", "assets": [ { "glob": "**/*", "input": "public" } ], "styles": [ "src/styles.css" ], "scripts": [] } } } } } } // app.routes.ts import {Routes} from '@angular/router'; import {SubjectListComponent} from './components/subject-list/subject-list.component'; import {SubjectComponent} from './components/subject/subject.component'; import {InnerSubjectListComponent} from './components/inner-subject-list/inner-subject-list.component'; export const routes: Routes = [ {path: '', pathMatch: 'full', redirectTo: 'subjects'}, {path: 'subjects', component: SubjectListComponent}, {path: 'subjects/arent-id/inner-subjects', component: InnerSubjectListComponent}, {path: 'subjects/arent-id/inner-subjects/:inner-subject-id', component: SubjectComponent}, ]; <!-- index.html --> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>BibleQuiz</title> <base href="/bible-quiz/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> </head> <body> <app-root></app-root> </body> </html> // subjects.service.ts import {Injectable} from '@angular/core'; import {HttpClient} from '@angular/common/http'; import {Observable} from 'rxjs'; import {ISubject} from '../models/ISubject'; import {environment} from '../../environments/environment'; @Injectable({ providedIn: 'root' }) export class SubjectsService { private subjectsUrl = environment.apiUrl + 'subjects.json'; constructor(private http: HttpClient) { } getSubjects(): Observable<ISubject[]> { return this.http.get<ISubject[]>(this.subjectsUrl); } } // environment.prod.ts export const environment = { production: true, apiUrl: '/bible-quiz/' }; // environment.ts export const environment = { production: false, apiUrl: '/' }; The environments have been added as it's my understanding they are needed due to GitHub Pages appending an extra /bible-quiz/ subroot to the page, but not sure this is really needed. This is my full app: https://github.com/francislainy/bible-quiz Continue reading...