Skip to content

Deploying an Angular App

Angular is a popular open-source web application framework maintained by Google. It provides a robust platform for building dynamic, scalable, and maintainable single-page applications (SPAs) using TypeScript. With powerful features like dependency injection, reactive forms, HTTP client, and powerful CLI tooling, Angular empowers developers to build complex applications with confidence.

This comprehensive guide walks through deploying an Angular app to Klutch.sh using either Nixpacks (automatic zero-configuration deployment) or a Dockerfile (manual container control). You’ll learn how to create and structure an Angular project, add sample components and services, configure environment variables, implement security best practices, set up monitoring, and troubleshoot common deployment issues. By the end of this guide, you’ll have a production-ready Angular application running on Klutch.sh’s global infrastructure.

Prerequisites

  • Node.js & npm (version 18+) – Download Node.js
  • Angular CLI installed globally (install with npm install -g @angular/cli)
  • Git installed locally and a GitHub account (Klutch.sh uses GitHub as the only git source)
  • Klutch.sh account with access to the dashboard at klutch.sh/app
  • Basic understanding of Angular, TypeScript, and the Node.js ecosystem

Getting Started: Create an Angular App

You can create a new Angular app using the Angular CLI or manually configure an existing project. Below is the recommended approach for a fresh Angular project.

1. Install Angular CLI

Install the Angular CLI globally:

Terminal window
npm install -g @angular/cli

2. Create a New Angular Project

Create a new Angular application with sensible defaults:

Terminal window
ng new my-angular-app --defaults
cd my-angular-app

This creates a new Angular project with:

  • TypeScript configuration
  • Angular routing
  • CSS styling
  • Testing setup with Karma and Jasmine
  • Build optimization

3. Project Structure

A typical Angular project structure looks like:

my-angular-app/
├── src/
│ ├── app/
│ │ ├── components/
│ │ │ ├── header/
│ │ │ ├── footer/
│ │ │ └── ...
│ │ ├── services/
│ │ │ ├── api.service.ts
│ │ │ ├── auth.service.ts
│ │ │ └── ...
│ │ ├── app.component.ts
│ │ ├── app.component.html
│ │ ├── app.component.css
│ │ └── app.module.ts
│ ├── assets/
│ ├── styles.css
│ ├── index.html
│ ├── main.ts
│ └── ...
├── angular.json
├── package.json
├── tsconfig.json
├── Dockerfile
└── README.md

4. Run the Development Server

Start the Angular development server:

Terminal window
ng serve

Navigate to http://localhost:4200 in your browser. The app will automatically reload if you change any of the source files.

5. Sample Component

Create a new component to display articles:

src/app/components/article-list/article-list.component.ts
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ArticleService, Article } from '../../services/article.service';
@Component({
selector: 'app-article-list',
standalone: true,
imports: [CommonModule],
template: `
<div class="articles">
<h2>Articles</h2>
<div *ngIf="loading" class="loading">Loading articles...</div>
<div *ngIf="!loading && articles.length === 0" class="no-articles">
No articles found.
</div>
<div *ngFor="let article of articles" class="article-card">
<h3>{{ article.title }}</h3>
<p>{{ article.content }}</p>
<small>By {{ article.author }} - {{ article.created_at | date }}</small>
</div>
</div>
`,
styles: [
`
.articles {
padding: 1rem;
}
.article-card {
border: 1px solid #ddd;
padding: 1rem;
margin-bottom: 1rem;
border-radius: 4px;
}
.article-card h3 {
margin: 0 0 0.5rem 0;
}
.loading,
.no-articles {
color: #666;
padding: 1rem;
}
`,
],
})
export class ArticleListComponent implements OnInit {
articles: Article[] = [];
loading = true;
constructor(private articleService: ArticleService) {}
ngOnInit(): void {
this.articleService.getArticles().subscribe((data) => {
this.articles = data;
this.loading = false;
});
}
}

6. Sample Service

Create a service to handle API calls:

src/app/services/article.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
export interface Article {
id: number;
title: string;
content: string;
author: string;
created_at: string;
}
@Injectable({
providedIn: 'root',
})
export class ArticleService {
private apiUrl = `${this.getBaseUrl()}/api/articles`;
constructor(private http: HttpClient) {}
private getBaseUrl(): string {
return window.location.origin;
}
getArticles(): Observable<Article[]> {
return this.http.get<Article[]>(this.apiUrl);
}
getArticle(id: number): Observable<Article> {
return this.http.get<Article>(`${this.apiUrl}/${id}`);
}
createArticle(article: Omit<Article, 'id' | 'created_at'>): Observable<Article> {
return this.http.post<Article>(this.apiUrl, article);
}
updateArticle(id: number, article: Partial<Article>): Observable<Article> {
return this.http.put<Article>(`${this.apiUrl}/${id}`, article);
}
deleteArticle(id: number): Observable<void> {
return this.http.delete<void>(`${this.apiUrl}/${id}`);
}
}

7. Root Component

Update your root component to include the article list:

src/app/app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { ArticleListComponent } from './components/article-list/article-list.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, ArticleListComponent],
template: `
<header>
<h1>Angular on Klutch.sh</h1>
<p>Deployed with Nixpacks and Docker</p>
</header>
<main>
<app-article-list></app-article-list>
</main>
<footer>
<p>&copy; 2024 My Angular App. All rights reserved.</p>
</footer>
<router-outlet></router-outlet>
`,
styles: [
`
header {
background-color: #1976d2;
color: white;
padding: 1rem;
text-align: center;
}
main {
min-height: calc(100vh - 200px);
max-width: 1200px;
margin: 0 auto;
}
footer {
background-color: #f5f5f5;
padding: 1rem;
text-align: center;
color: #666;
}
`,
],
})
export class AppComponent {
title = 'my-angular-app';
}

8. Module Configuration

Ensure your main module imports necessary Angular modules:

src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, HttpClientModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}

Local Production Build Test

Before deploying, test the production build locally:

Terminal window
ng build --configuration production
npm install -g http-server
cd dist/my-angular-app
http-server -p 4200

Visit http://localhost:4200 to verify that your app renders correctly in production mode.


Deploying with Nixpacks

Nixpacks automatically detects your Node.js/Angular application and configures build and runtime environments without requiring a Dockerfile. This is the simplest deployment method for Angular apps.

Prerequisites for Nixpacks Deployment

  • Your Angular project pushed to a GitHub repository
  • Valid package.json with build and start scripts
  • No Dockerfile in the repository root (if one exists, Klutch.sh will use Docker instead)

Steps to Deploy with Nixpacks

  1. Push Your Angular Project to GitHub

    Initialize and push your project to GitHub if you haven’t already:

    Terminal window
    git init
    git add .
    git commit -m "Initial Angular app"
    git branch -M main
    git remote add origin git@github.com:YOUR_USERNAME/YOUR_REPO.git
    git push -u origin main
  2. Log In to Klutch.sh Dashboard

    Go to klutch.sh/app and sign in with your GitHub account.

  3. Create a Project

    Navigate to the Projects section and create a new project for your Angular app.

  4. Create an App

    Click “Create App” and select your GitHub repository.

  5. Select the Branch

    Choose the branch you want to deploy (typically main).

  6. Configure Traffic Type

    Select HTTP as the traffic type for Angular (a web framework serving HTML/assets).

  7. Set the Internal Port

    Set the internal port to 4200 – this is the port where your Angular dev server listens. For production builds served by Node.js, this may differ, but 4200 is the Angular standard.

  8. Add Environment Variables (Optional)

    Add any environment variables your Angular app requires:

    NODE_ENV=production
    API_URL=https://api.example.com
    LOG_LEVEL=info

    If you need to customize the Nixpacks build or start command:

    • BUILD_COMMAND: Override the default build command (e.g., ng build --configuration production)
    • START_COMMAND: Override the default start command for serving the built Angular app
  9. Configure Compute Resources

    Select your region, compute size, and number of instances based on expected traffic.

  10. Deploy

    Click “Create” to start the deployment. Nixpacks will automatically build and deploy your Angular app. Your app will be available at a URL like https://example-app.klutch.sh.


Deploying with Docker

For more control over your deployment environment, you can use a Dockerfile. Klutch.sh automatically detects a Dockerfile in your repository root and uses it for deployment.

Creating a Dockerfile for Angular

Create a Dockerfile in the root of your Angular project:

# === Build stage ===
FROM node:20-alpine AS builder
WORKDIR /app
# Install Angular CLI and dependencies
RUN npm install -g @angular/cli
COPY package*.json ./
RUN npm install
# Copy the rest of the source code
COPY . .
# Build the Angular app for production
RUN ng build --configuration production
# === Runtime stage ===
FROM node:20-alpine AS runtime
WORKDIR /app
# Install a simple HTTP server to serve the Angular app
RUN npm install -g http-server
# Copy built assets from builder
COPY --from=builder /app/dist/my-angular-app ./dist
# Set the port for the server to listen on
ENV PORT=4200
EXPOSE 4200
# Start the HTTP server serving the Angular distribution
CMD ["http-server", "dist", "-p", "4200", "--gzip"]

Dockerfile Notes

  • Builder stage: Installs Angular CLI and builds the Angular app for production using the Angular compiler.
  • Runtime stage: Uses a lightweight Node.js Alpine image with http-server to serve the compiled Angular application.
  • Port: The PORT environment variable is set to 4200, which is the recommended internal port for Angular.
  • GZip: The --gzip flag enables automatic gzip compression for faster asset delivery.
  • Multi-stage build: Reduces final image size by excluding build tools and dev dependencies.

Steps to Deploy with Docker

  1. Create a Dockerfile

    Add the Dockerfile (shown above) to the root of your Angular repository.

  2. Test Locally (Optional)

    Build and test the Docker image locally:

    Terminal window
    docker build -t angular-app:latest .
    docker run -p 4200:4200 angular-app:latest

    Visit http://localhost:4200 to verify.

  3. Push to GitHub

    Commit and push the Dockerfile and your code:

    Terminal window
    git add Dockerfile
    git commit -m "Add Dockerfile for production deployment"
    git push origin main
  4. Create an App in Klutch.sh

    Go to klutch.sh/app, navigate to “Create App”, and select your repository.

  5. Configure the App
    • Traffic Type: Select HTTP
    • Internal Port: Set to 4200
    • Environment Variables: Add any required runtime variables
  6. Deploy

    Klutch.sh automatically detects the Dockerfile and uses it to build and deploy your app. Your app will be available at https://example-app.klutch.sh.


Backend API Integration

Many Angular applications require a backend API for data persistence. You can run a separate backend service or combine Angular with a backend server.

Environment Configuration

Create environment configuration files for development and production:

src/environments/environment.ts
export const environment = {
production: false,
apiUrl: 'http://localhost:3000/api',
};
// src/environments/environment.prod.ts
export const environment = {
production: true,
apiUrl: 'https://example-app.klutch.sh/api',
};

Use the environment in your services:

import { environment } from '../../environments/environment';
@Injectable({
providedIn: 'root',
})
export class ApiService {
private apiUrl = environment.apiUrl;
constructor(private http: HttpClient) {}
get<T>(endpoint: string): Observable<T> {
return this.http.get<T>(`${this.apiUrl}${endpoint}`);
}
post<T>(endpoint: string, data: any): Observable<T> {
return this.http.post<T>(`${this.apiUrl}${endpoint}`, data);
}
}

Environment Variables

Define all environment variables in the Klutch.sh dashboard. Here’s a recommended set for production:

NODE_ENV=production
API_URL=https://api.example.com
LOG_LEVEL=info
DEBUG=false
ANALYTICS_KEY=your-analytics-key

Accessing Environment Variables in Angular

Access environment variables through Angular’s environment configuration:

import { environment } from '../../environments/environment';
export class ConfigService {
getApiUrl(): string {
return environment.apiUrl;
}
isProduction(): boolean {
return environment.production;
}
}

Persistent Storage

If your Angular app needs to store files or user-generated content, you can use a backend service with persistent volumes. Refer to your backend documentation for persistent storage setup.

Adding Persistent Volumes to Backend Services

If running a backend on Klutch.sh:

  1. In the Klutch.sh dashboard, go to your backend app’s Volumes section.
  2. Click Add Volume.
  3. Set the mount path (e.g., /data, /uploads, or /var/www/uploads).
  4. Set the size (e.g., 1 GiB, 10 GiB).
  5. Save and redeploy your backend app.

Security Best Practices

1. HTTPS/SSL Enforcement

Klutch.sh automatically provides HTTPS for all deployed apps. Ensure your Angular app redirects HTTP to HTTPS:

src/app/http-interceptors/https.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class HttpsInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (req.url.startsWith('http://') && !req.url.includes('localhost')) {
const httpsReq = req.clone({ url: req.url.replace('http://', 'https://') });
return next.handle(httpsReq);
}
return next.handle(req);
}
}

2. CORS Configuration

Configure CORS in your backend API to allow requests from your Angular app:

// Backend example (if using Express)
app.use(cors({
origin: ['https://example-app.klutch.sh', 'https://custom-domain.com'],
credentials: true,
}));

3. Content Security Policy

Add security headers to your Angular app via your backend or server configuration:

// Backend Express example
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '1; mode=block');
res.setHeader('Content-Security-Policy', "default-src 'self'");
next();
});

4. Authentication & Authorization

Implement token-based authentication with Angular:

src/app/services/auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, BehaviorSubject } from 'rxjs';
import { map } from 'rxjs/operators';
interface LoginRequest {
email: string;
password: string;
}
interface AuthResponse {
token: string;
user: { id: string; email: string };
}
@Injectable({
providedIn: 'root',
})
export class AuthService {
private apiUrl = '/api/auth';
private currentUserSubject: BehaviorSubject<AuthResponse | null>;
public currentUser$: Observable<AuthResponse | null>;
constructor(private http: HttpClient) {
this.currentUserSubject = new BehaviorSubject<AuthResponse | null>(
JSON.parse(localStorage.getItem('currentUser') || 'null')
);
this.currentUser$ = this.currentUserSubject.asObservable();
}
login(credentials: LoginRequest): Observable<AuthResponse> {
return this.http.post<AuthResponse>(`${this.apiUrl}/login`, credentials).pipe(
map((response) => {
localStorage.setItem('currentUser', JSON.stringify(response));
this.currentUserSubject.next(response);
return response;
})
);
}
logout(): void {
localStorage.removeItem('currentUser');
this.currentUserSubject.next(null);
}
getToken(): string | null {
return this.currentUserSubject.value?.token || null;
}
}

5. HTTP Interceptors for Security

Create an interceptor to add authentication tokens to requests:

src/app/http-interceptors/auth.interceptor.ts
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { AuthService } from '../services/auth.service';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(
request: HttpRequest<unknown>,
next: HttpHandler
): Observable<HttpEvent<unknown>> {
const token = this.authService.getToken();
if (token) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
},
});
}
return next.handle(request);
}
}

6. Input Validation

Validate all user inputs in your components and services:

src/app/forms/article-form.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-article-form',
template: `
<form [formGroup]="articleForm" (ngSubmit)="onSubmit()">
<input
type="text"
formControlName="title"
placeholder="Article Title"
required
/>
<textarea
formControlName="content"
placeholder="Article Content"
required
></textarea>
<button type="submit" [disabled]="!articleForm.valid">Submit</button>
</form>
`,
})
export class ArticleFormComponent {
articleForm: FormGroup;
constructor(private fb: FormBuilder) {
this.articleForm = this.fb.group({
title: ['', [Validators.required, Validators.maxLength(255)]],
content: ['', [Validators.required, Validators.maxLength(10000)]],
});
}
onSubmit(): void {
if (this.articleForm.valid) {
// Submit form data
}
}
}

7. Secure Storage

Never store sensitive data in localStorage. Use secure, HTTP-only cookies managed by your backend:

// Good: Backend sets secure cookies
// Bad: Storing sensitive data in localStorage
// localStorage.setItem('apiKey', 'sensitive-key'); // DON'T DO THIS

Monitoring and Logging

Health Check Endpoint

Implement a health check endpoint in your backend if applicable:

// Backend example
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
});
});

Client-Side Error Handling

Implement comprehensive error handling in your Angular app:

src/app/services/error-handler.service.ts
import { Injectable, ErrorHandler, Injector } from '@angular/core';
@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
constructor(private injector: Injector) {}
handleError(error: Error | any): void {
const chunkFailedMessage = /Loading chunk \d+ failed/g.test(error.message);
if (chunkFailedMessage) {
window.location.reload();
}
console.error('Global error handler:', error);
// Send error to monitoring service
// this.monitoringService.logError(error);
}
}

Structured Logging

Implement structured logging for production monitoring:

src/app/services/logger.service.ts
import { Injectable } from '@angular/core';
export interface LogEntry {
timestamp: string;
level: 'info' | 'warn' | 'error';
message: string;
data?: any;
}
@Injectable({
providedIn: 'root',
})
export class LoggerService {
log(level: string, message: string, data?: any): void {
const entry: LogEntry = {
timestamp: new Date().toISOString(),
level: level as any,
message,
data,
};
console.log(JSON.stringify(entry));
// Send to monitoring service
}
info(message: string, data?: any): void {
this.log('info', message, data);
}
warn(message: string, data?: any): void {
this.log('warn', message, data);
}
error(message: string, data?: any): void {
this.log('error', message, data);
}
}

Custom Domains

To use a custom domain with your Klutch.sh-deployed Angular app:

1. Add the Domain in Klutch.sh

In the Klutch.sh dashboard, go to your app’s settings and add your custom domain (e.g., app.example.com).

2. Update Your DNS Provider

Update your DNS records with the CNAME provided by Klutch.sh:

CNAME: app.example.com → example-app.klutch.sh

3. Wait for DNS Propagation

DNS changes can take up to 48 hours to propagate. Use tools to verify:

Terminal window
nslookup app.example.com
# or
dig app.example.com

Once propagated, your Angular app will be accessible at your custom domain with automatic HTTPS.


Troubleshooting

Issue 1: Build Fails with Memory Error

Error: ng build fails with “JavaScript heap out of memory”

Solutions:

  • Increase Node memory: NODE_OPTIONS=--max-old-space-size=4096 ng build
  • Set BUILD_COMMAND in Klutch.sh: NODE_OPTIONS=--max-old-space-size=4096 ng build --configuration production
  • Optimize your Angular code and reduce bundle size
  • Lazy load components and modules

Issue 2: Port Already in Use

Error: EADDRINUSE: address already in use :::4200

Solutions:

  • Change the port in angular.json or use ng serve --port 4300
  • Ensure the internal port in Klutch.sh matches your configuration
  • Kill the process using the port: lsof -ti:4200 | xargs kill -9

Issue 3: API Calls Return 404

Error: API endpoints return 404 in production

Solutions:

  • Verify API_URL environment variable is set correctly
  • Check that your backend is deployed and accessible
  • Use absolute URLs in your Angular app instead of relative URLs
  • Implement proper error handling and logging in your HTTP service

Issue 4: Build Time Exceeds Limits

Error: Build timeout or excessive build time

Solutions:

  • Disable source maps in production: ng build --configuration production --source-map=false
  • Use Ahead-of-Time (AOT) compilation (enabled by default in production builds)
  • Remove unused dependencies
  • Implement code splitting and lazy loading
  • Set BUILD_COMMAND: ng build --configuration production --source-map=false

Issue 5: Assets Not Loading

Error: CSS, images, or JavaScript not loading in production

Solutions:

  • Ensure all assets are in the src/assets folder
  • Check that base href is correct in index.html: <base href="/">
  • Verify assets are included in angular.json build configuration
  • Check browser console for 404 errors and adjust asset paths

Best Practices

1. Use Lazy Loading

Load modules only when needed to reduce initial bundle size:

src/app/app-routing.module.ts
const routes: Routes = [
{
path: 'articles',
loadChildren: () => import('./modules/articles/articles.module').then((m) => m.ArticlesModule),
},
];

2. Implement OnPush Change Detection

Optimize change detection for better performance:

@Component({
selector: 'app-article-card',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<div>{{ article.title }}</div>`,
})
export class ArticleCardComponent {
@Input() article: Article;
}

3. Use Reactive Forms

Build more scalable forms with RxJS:

src/app/forms/advanced-form.component.ts
this.form = this.fb.group({
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(8)]],
confirmPassword: ['', Validators.required],
}, {
validators: this.passwordMatchValidator,
});

4. Implement Route Guards

Protect routes based on authentication and authorization:

src/app/guards/auth.guard.ts
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (this.authService.isAuthenticated()) {
return true;
}
this.router.navigate(['/login']);
return false;
}
}

5. Optimize Bundle Size

Monitor and reduce your application bundle:

Terminal window
# Analyze bundle size
ng build --stats-json
npm install -g webpack-bundle-analyzer
webpack-bundle-analyzer dist/my-angular-app/stats.json

6. Implement Progressive Web App (PWA) Features

Add offline support and installability:

Terminal window
ng add @angular/pwa

7. Use Environment-Specific Configurations

Maintain separate configurations for development, staging, and production:

src/environments/environment.staging.ts
export const environment = {
production: false,
apiUrl: 'https://staging-api.example.com',
};

8. Keep Dependencies Updated

Regularly update Angular and related packages:

Terminal window
ng update @angular/cli @angular/core
npm audit fix

9. Implement Proper Error Handling

Use Angular’s error handling mechanisms:

src/app/http-interceptors/error.interceptor.ts
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
catchError((error) => {
console.error('HTTP error:', error);
// Handle error appropriately
return throwError(() => error);
})
);
}
}

10. Document Your Code

Add comprehensive documentation for maintainability:

/**
* ArticleService - Handles all article-related API calls
*
* Methods:
* - getArticles(): Retrieves all articles
* - getArticle(id): Retrieves a single article by ID
* - createArticle(data): Creates a new article
* - updateArticle(id, data): Updates an existing article
* - deleteArticle(id): Deletes an article
*/
@Injectable({
providedIn: 'root',
})
export class ArticleService { }

Verifying Your Deployment

After deployment completes:

  1. Check the App URL: Visit your app at https://example-app.klutch.sh or your custom domain.
  2. Verify Pages Render: Ensure all pages load and Angular components render correctly.
  3. Test API Integration: Test API calls to your backend if applicable.
  4. Check Console: Open the browser console (F12) and verify no errors are present.
  5. Test User Interactions: Verify form submissions, navigation, and dynamic content work.
  6. Review Performance: Use Lighthouse or WebPageTest to verify performance metrics.
  7. Check Logs: Review the Klutch.sh dashboard for deployment logs and any runtime errors.

If your app doesn’t work as expected, review the troubleshooting section and check the logs in the Klutch.sh dashboard.


External Resources


Deploying an Angular app to Klutch.sh is straightforward with Nixpacks for automatic deployment or Docker for fine-grained control. By following this guide, you’ve learned how to scaffold an Angular project, build components and services, configure environment variables, implement security best practices, set up monitoring, and troubleshoot common issues. Your Angular application is now running on Klutch.sh’s global infrastructure with automatic HTTPS, custom domain support, and production-grade performance. For additional help or questions, consult the official Angular documentation or contact Klutch.sh support.