Project Structure & Bootstrapping

Angular · Lesson 3 of 29 6 min read Updated

A new Angular project contains about twenty files, and it is easy to feel lost. Most of them are configuration you rarely touch. In this lesson you will learn which files matter, how the app starts in the browser (this is called bootstrapping), and where your own code goes.

The project folder

Here is the layout of the canteen project created in the previous lesson:

Text
canteen/
  angular.json          workspace and build settings
  package.json          npm packages and scripts
  tsconfig.json         TypeScript settings (plus tsconfig.app.json, tsconfig.spec.json)
  public/               static files copied as-is (favicon.ico, images)
  node_modules/         downloaded packages (never edit, never commit)
  src/
    index.html          the single HTML page
    main.ts             the entry point that starts Angular
    styles.css          global styles for the whole app
    app/
      app.ts            the root component class
      app.html          the root component template
      app.css           the root component styles
      app.spec.ts       tests for the root component
      app.config.ts     application-wide providers
      app.routes.ts     the list of routes (URLs)

You will spend almost all your time inside src/app. Global CSS such as fonts and body colours go in src/styles.css. Images that you refer to by URL, such as /logo.svg, go in public/.

FileEdit it?Why
src/app/*Yes, all the timeYour components, services and routes
src/styles.cssSometimesGlobal styles
angular.jsonRarelyBuild options, budgets, extra global styles
package.jsonThrough npmAdd packages with npm install or ng add
node_modules/NeverRecreated by npm install

How the app starts

When the browser opens your app, four files work together, in this order.

1. src/index.html is the only HTML page. Its body contains one custom tag:

HTML
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Canteen</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
  <app-root></app-root>
</body>
</html>

<app-root> is empty at first. Angular will fill it with the root component. The <base href="/"> tag tells the router where the app's URLs begin.

2. src/main.ts is the entry point. The build tool starts here and follows every import:

TypeScript
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { App } from './app/app';

bootstrapApplication(App, appConfig).catch((err) => console.error(err));

bootstrapApplication creates the application, applies the configuration and renders the App component into the element that matches its selector, <app-root>.

3. src/app/app.config.ts lists providers: services and features that the whole app can use.

TypeScript
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideBrowserGlobalErrorListeners(),
    provideRouter(routes),
  ],
};

provideBrowserGlobalErrorListeners() makes Angular report uncaught errors in the browser, and provideRouter(routes) turns on routing. Later you will add more here, such as provideHttpClient() for calling APIs.

4. src/app/app.ts is the root component, the top of your component tree. Every other component appears inside it.

TypeScript
import { Component, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router';

@Component({
  selector: 'app-root',
  imports: [RouterOutlet],
  templateUrl: './app.html',
  styleUrl: './app.css',
})
export class App {
  protected readonly title = signal('Canteen');
}

The template lives in a separate file, app.html, and the styles in app.css. imports: [RouterOutlet] lets the template use <router-outlet />, the place where routed pages appear.

Replace the welcome page

The generated app.html is a long welcome page. Delete everything in it and write your own content:

HTML
<header>
  <h1>{{ title() }} - Sharma Ji's College Canteen</h1>
  <p>Order before 12:30 pm for lunch pickup.</p>
</header>

<router-outlet />

Save the file while ng serve is running and the browser shows:

Output
Canteen - Sharma Ji's College Canteen
Order before 12:30 pm for lunch pickup.

{{ title() }} reads the title signal from the class. The protected keyword means the template can use it but other classes cannot, which keeps the component's public surface small.

Inside angular.json

angular.json describes the workspace: one or more projects and how to build, serve and test them. A few settings are worth knowing:

  • "browser": "src/main.ts" is the entry point.
  • "assets" copies everything in public/ into the build.
  • "styles": ["src/styles.css"] lists global stylesheets. Add a library's CSS file here if it needs one.
  • "budgets" makes the production build warn or fail if your bundle grows too large (by default it warns at 500 kB and fails at 1 MB for the initial bundle).

A workspace can hold several apps and libraries; extra ones are created in the projects/ folder with ng generate application or ng generate library.

Common mistakes

  • Removing <app-root> from index.html. Angular then has nowhere to render, and the page stays blank with an error in the console about the selector not matching any element.
  • Putting images in src/ instead of public/. Files outside the configured assets are not copied to the build, so the image shows as broken.
  • Editing files in node_modules. Your changes disappear on the next npm install. Configure things in your own code instead.
  • Committing node_modules or dist. The generated .gitignore already excludes them; keep it that way.

Key points

  • Your code lives in src/app; global styles go in src/styles.css; static files go in public/.
  • index.html contains <app-root>, which Angular fills with the root App component.
  • main.ts calls bootstrapApplication(App, appConfig) to start the app.
  • app.config.ts lists app-wide providers such as provideRouter(routes).
  • angular.json holds build settings, assets, global styles and size budgets.

Exercise

In your canteen project, change the page title in index.html to "Campus Canteen", change the title signal to "Campus Canteen" and replace app.html with a heading and a paragraph giving the canteen's opening hours (8 am to 6 pm). Then add a global style in src/styles.css that sets the body font to system-ui and the margin to 0.

Show solution
TypeScript
export class App {
  protected readonly title = signal('Campus Canteen');
}
HTML
<h1>{{ title() }}</h1>
<p>Open daily from 8 am to 6 pm.</p>

<router-outlet />
CSS
body {
  margin: 0;
  font-family: system-ui, sans-serif;
}

The <title> in index.html changes the browser tab text, while the signal changes the heading inside the page. Global body styles belong in src/styles.css, not in app.css, because component styles only apply to that component's own template.

Quick Quiz

1. Which function starts a standalone Angular application in main.ts?

2. Where do you register app-wide features such as the router?

3. Where should a logo image that you link as /logo.svg go in a new project?

Learn Angular with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call