Angular is Google's framework for building large, structured web applications in TypeScript. It has changed a lot in the last few releases: components are standalone by default, signals handle state, templates have built-in @if and @for blocks, and server-side rendering is part of the CLI. This guide walks through the architecture, components, data binding, routing, forms and HTTP the way current Angular does them, and ends with how to build and host the result.
A modern Angular app is a tree of standalone components. Each component holds its state in signals, receives data through input() and sends events through output(), and gets shared logic from services through inject(). The router lazy-loads pages, reactive forms handle input, and HttpClient talks to your API. ng build produces static files you can host anywhere; server-side rendering needs Node.js.
1. Before you start
You need:
- Node.js, a current LTS release (22 or 24). Check with
node -v. - The Angular CLI, installed with
npm install -g @angular/cli. - An editor with TypeScript support, such as VS Code with the Angular Language Service extension.
- Working knowledge of HTML, CSS and TypeScript.
Create and run a project:
ng new my-app
cd my-app
ng serveng new asks which stylesheet format you want and whether to enable server-side rendering (SSR). Open http://localhost:4200 to see the app. Check which Angular versions are currently supported on the official site, angular.dev, and keep your project on one of them.
2. The architecture in one picture
| Building block | What it does | How you create it |
|---|---|---|
| Component | A piece of UI: a TypeScript class plus a template and styles | ng generate component name |
| Template | HTML with bindings and control-flow blocks | Inside the component |
| Signal | A value that tells Angular when it changes | signal(), computed() |
| Service | Shared logic or data, such as API calls | ng generate service name |
| Directive | Adds behaviour to an existing element | ng generate directive name |
| Pipe | Formats a value in a template, such as a date | ng generate pipe name |
| Router | Maps URLs to components | app.routes.ts |
Older tutorials build everything around NgModule. Current Angular doesn't need it: each component lists what it uses in its own imports array, and the app starts from a configuration file. You will still meet NgModules in older codebases, and they still work.
3. Components, signals and data binding
A component with its own state, an input from its parent and an event back to the parent:
import { Component, computed, input, output, signal } from '@angular/core';
@Component({
selector: 'app-greeting',
template: `
<h2>Hello, {{ name() }}!</h2>
<p>Clicked {{ count() }} times (doubled: {{ doubled() }})</p>
<button (click)="increment()">Click me</button>
`,
})
export class Greeting {
name = input.required<string>(); // data from the parent
clicked = output<number>(); // event to the parent
count = signal(0); // local state
doubled = computed(() => this.count() * 2);
increment() {
this.count.update(c => c + 1);
this.clicked.emit(this.count());
}
}The parent imports Greeting in its imports array and uses it like this:
<app-greeting [name]="userName" (clicked)="onClicked($event)" />The four kinds of binding:
- Interpolation,
{{ name() }}, prints a value. - Property binding,
[value]="username", sets a DOM property or a component input. - Event binding,
(click)="save()", calls a method when an event fires. - Two-way binding,
[(ngModel)]or amodel()input, keeps a value and a field in sync.
A signal is read by calling it (count()) and changed with set() or update(). computed() derives a value and recalculates only when its inputs change. For the rare side effect that must follow a signal, such as saving to storage, use effect().
4. Templates: control flow and deferred loading
Templates use built-in blocks instead of the older *ngIf and *ngFor directives:
@if (products().length) {
<ul>
@for (p of products(); track p.id) {
<li>{{ p.name }} - {{ p.price | currency:'INR' }}</li>
}
</ul>
} @else {
<p>No products yet.</p>
}
@defer (on viewport) {
<app-reviews />
} @placeholder {
<p>Loading reviews...</p>
}track tells Angular how to identify each item, so it updates only the rows that changed. @defer loads a component's code only when it is needed, here when it scrolls into view, which keeps the first download small.
5. Services and dependency injection
Put API calls and shared state in a service, and get it with inject():
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
export interface Product { id: number; name: string; price: number; }
@Injectable({ providedIn: 'root' })
export class ProductService {
private http = inject(HttpClient);
list() {
return this.http.get<Product[]>('/api/products');
}
}providedIn: 'root' creates one shared instance for the whole app. In a component, turn the request into a signal:
import { toSignal } from '@angular/core/rxjs-interop';
products = toSignal(inject(ProductService).list(), { initialValue: [] });HttpClient returns RxJS observables. Use RxJS operators such as catchError and retry for error handling, and an interceptor for anything every request needs.
6. App configuration, routing and guards
The app starts from app.config.ts:
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withFetch } from '@angular/common/http';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes), provideHttpClient(withFetch())],
};Routes lazy-load each page and protect private ones with a functional guard:
import { Routes } from '@angular/router';
import { authGuard } from './auth.guard';
export const routes: Routes = [
{ path: '', loadComponent: () => import('./home').then(m => m.Home) },
{ path: 'admin', canActivate: [authGuard],
loadComponent: () => import('./admin').then(m => m.Admin) },
{ path: '**', redirectTo: '' },
];A guard only decides which screens a user sees. The real protection belongs on the server, which must check the session on every API call.
7. Forms
Reactive forms are the most flexible choice for anything beyond a single field:
import { Component, inject } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
selector: 'app-signup',
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="form" (ngSubmit)="submit()">
<input formControlName="email" type="email" />
<button [disabled]="form.invalid">Sign up</button>
</form>
`,
})
export class Signup {
form = inject(FormBuilder).nonNullable.group({
email: ['', [Validators.required, Validators.email]],
});
submit() { console.log(this.form.getRawValue()); }
}Template-driven forms with ngModel still suit very small forms. Always validate again on the server.
8. Performance and security
- Production builds are optimised by default.
ng buildcompiles ahead of time, removes unused code and adds content hashes to file names. - Lazy-load routes and
@deferheavy components so the first page stays light. - Use
trackin every@for. - Angular escapes values in templates, which blocks most cross-site scripting. Avoid
bypassSecurityTrust...calls unless you fully control the content. - Don't store login tokens in localStorage. Let the server set an httpOnly cookie, as shown in Developing the user authentication service in MEAN stack.
- Serve everything over HTTPS, and keep Angular and its dependencies updated with
ng update.
State libraries such as NgRx are still available for very large apps, but services with signals cover most apps without one.
9. Building and hosting your app
Run ng build. Without SSR, the output in dist/my-app/browser/ is plain static files (HTML, JavaScript and CSS) that any web server can serve.
- Build.Run
ng buildon your computer or in CI. - Upload.Copy the contents of
dist/my-app/browser/into your site's folder, usuallypublic_html, with the File Manager or FTP. - Add a fallback rule.Angular handles URLs in the browser, so the server must return
index.htmlfor paths that aren't real files. Put the.htaccessbelow next toindex.html. - Test a deep link.Open a URL such as
/admindirectly and reload it. It should load, not show a 404.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^ index.html [L]With SSR enabled (ng new with SSR, or ng add @angular/ssr later), the build also produces a Node.js server in dist/my-app/server/, and that server must keep running.
10. Running Angular on Domain India
| What you deploy | Where it fits | Notes |
|---|---|---|
| Static Angular build (no SSR) | cPanel, DirectAdmin or Webuzo shared hosting | Upload the browser folder and add the .htaccess rule above |
| Angular with SSR | App Platform, or Setup Node.js App on cPanel | cPanel's Node.js tool offers versions 20, 22 and 24; use 22 or 24 |
| Angular plus your own API and database | App Platform or VPS | Node.js apps are detected automatically on the App Platform |
On our cPanel servers, nginx may keep serving a cached copy of an unchanged URL for up to two hours after an upload. If you don't see your new build, add ?t=1 to the URL to check it. Build on your own computer or in CI, not on shared hosting: the build tools need more memory and processes than a shared account allows. See Deploy a Node.js app on shared hosting and Getting started with the App Platform.
- 25 GB NVMe SSD Storage
- 50 GB Monthly Bandwidth
- 1 Website
- 10 Email Accounts
- 512 MB RAM per app
- 1 vCPU
- 5 GB NVMe SSD
- PostgreSQL Database
Prices on the cards are live Domain India list prices and exclude 18% GST.
Do I still need NgModule in Angular?
No. In current Angular releases, components are standalone by default and list their own dependencies in an imports array, and the app starts from a configuration file with providers such as provideRouter and provideHttpClient. NgModules still work, so older apps don't have to be rewritten at once.
What are signals in Angular?
Signals are values that notify Angular when they change. You create one with signal(), read it by calling it, change it with set() or update(), and derive values with computed(). They make change tracking precise and replace many uses of RxJS for local component state.
Can I host an Angular app on shared hosting?
Yes, if it is a static build without server-side rendering. Upload the contents of the dist browser folder to public_html and add an .htaccess rule that returns index.html for paths that are not real files, so deep links and page reloads work.
Why does my Angular route show a 404 after a page reload?
The web server looks for a real file at that path and doesn't find one. Add a rewrite rule that sends every path that isn't an existing file or folder to index.html, so Angular's router can handle it.
Which Node.js version should I use for Angular?
A current Node.js LTS release, such as 22 or 24, that your Angular version supports. Node.js 20 has reached end of life, so avoid it for new projects.
Is Angular Universal still used for server-side rendering?
Server-side rendering is now part of Angular itself through the @angular/ssr package. Enable it when you create the project with ng new, or add it later with ng add @angular/ssr. The SSR build needs a running Node.js server.
Ready to put your app online? Host a static build on cPanel hosting, run SSR or a full-stack app on the App Platform, or open a support ticket if you're unsure which fits.
Node.js apps are detected and built automatically, with free SSL and your own domain.
See App Platform plans