Posted in

Angular 22 Complete Setup and Project Structure: A Proven Beginner Guide

Angular 22 project structure folder tree

Understanding Angular 22 project structure is easy to overlook when starting out, but knowing where your own code should live is what matters once the project starts growing.

In this practical Angular 22 tutorial, we’ll build an Angular 22 project structure that scales beyond a demo, understand its important files and folders, create our first feature, and organize the project in a structure that can scale beyond a demo.

What We’ll Build

Instead of creating another basic Hello World application, we’ll start a small Task Manager project.

By the end, our application will have a structure similar to:

src/
├── app/
│   ├── core/
│   ├── features/
│   │   └── tasks/
│   ├── shared/
│   ├── app.config.ts
│   ├── app.routes.ts
│   ├── app.ts
│   └── app.html
├── index.html
├── main.ts
└── styles.css

This gives us a useful foundation for future Angular projects — and it’s the same Angular 22 project structure pattern you can reuse on any scaled app.

Prerequisites

Before starting, verify that Node.js and npm are installed.

node --version
npm --version

Angular’s current installation documentation should always be checked before installing because supported Node.js versions change over time.

Step 1: Install Angular CLI

Open your terminal:

npm install -g @angular/cli

Verify the installation:

For platform-specific setup details or troubleshooting, see the official Angular CLI setup guide. You should see information about Angular CLI, Angular, Node.js, npm and your operating system.

If you’re setting this up on Windows and run into any environment issues, check out our step-by-step guide to installing Angular on Windows for a more detailed walkthrough.

Step 2: Create an Angular 22 Application

Create the project:

ng new angular-task-manager

Angular CLI will ask you several configuration questions.

For a modern application, routing is useful because our Task Manager may eventually contain pages such as:

/tasks
/tasks/new
/tasks/123
/settings

Enter the project:

Start the development server:

Then visit:

A useful shortcut is:

Angular will compile the application and open it in your default browser.

Step 3: Understand main.ts

One of the first files Angular executes is:

A modern standalone Angular application bootstraps the root component rather than starting with the old NgModule-first architecture.

Conceptually, you’ll see something similar to:

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));

Think of main.ts as the starting point of the Angular application.

It tells Angular:

Start this application using this root component and configuration.

Most applications rarely require frequent changes to this file.

Step 4: Understand app.config.ts

Open:

Application-level providers can be configured here.

For example:

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

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

Later you may configure things such as HTTP, routing, animations or other application-wide services here.

A useful mental model is:

main.ts
   ↓
app.config.ts
   ↓
root component
   ↓
features

Step 5: Understand app.routes.ts

Routing configuration belongs in:

For example:

import { Routes } from '@angular/router';

export const routes: Routes = [];

We’ll add feature routes later.

Keeping routing separate prevents the root component from becoming responsible for navigation configuration.

Step 6: Don’t Put Everything Inside app/

A common beginner structure looks like:

app/
├── task-list
├── task-form
├── navbar
├── auth-service
├── task-service
├── user-service
├── button
├── modal
└── ...

This works initially.

After several months, however, developers struggle to answer:

  • Which files belong together?
  • Which service is global?
  • Which component is reusable?
  • Where should the next feature go?

A better structure organizes code according to responsibility.

Step 7: Create core, shared and features (the core of your Angular 22 project structure)

Inside src/app, create:

Their responsibilities should be different.

core/

Use core for application-wide functionality.

Example:

core/
├── guards/
├── interceptors/
├── services/
└── models/

Potential examples:

auth.service.ts
auth.guard.ts
api.interceptor.ts

Avoid putting ordinary feature components here.

shared/

Use shared for reusable UI and utilities.

Example:

shared/
├── components/
├── directives/
├── pipes/
└── utils/

Examples:

button/
modal/
loading-spinner/
truncate.pipe.ts

The important test is:

Could multiple unrelated features reasonably reuse this?

If yes, shared may be appropriate.

features/

Feature-specific functionality belongs here.

For our application:

features/
└── tasks/

Later we might add:

features/
├── tasks/
├── authentication/
├── dashboard/
└── settings/

This is easier to navigate because code that changes together generally lives together.

Step 8: Generate the Task List

Run:

ng generate component features/tasks/task-list

or:

ng g c features/tasks/task-list

Angular CLI creates the component files for us.

For a deeper look at how Angular components are structured and how they fit together, see our Angular Components tutorial.

Now add a simple implementation:

import { Component } from '@angular/core';

@Component({
  selector: 'app-task-list',
  standalone: true,
  template: `
    <section>
      <h2>My Tasks</h2>

      <ul>
        <li>Learn Angular project structure</li>
        <li>Build task component</li>
        <li>Add routing</li>
      </ul>
    </section>
  `
})
export class TaskList {}

We now have actual feature code instead of a meaningless demo component.

Step 9: Add a Task Route

Update app.routes.ts:

import { Routes } from '@angular/router';
import { TaskList } from './features/tasks/task-list/task-list';

export const routes: Routes = [
  {
    path: 'tasks',
    component: TaskList
  },
  {
    path: '',
    redirectTo: 'tasks',
    pathMatch: 'full'
  }
];

The application now redirects / to /tasks.

Step 10: Add router-outlet

The root component needs somewhere to render the active route.

Import RouterOutlet and use:

<router-outlet></router-outlet>

Now visiting:

http://localhost:4200/tasks

renders our Task List.

Step 11: Create a Task Interface

Inside the tasks feature, create:

Add:

export interface Task {
  id: number;
  title: string;
  completed: boolean;
}

Then our feature can work with properly typed data:

tasks: Task[] = [
  {
    id: 1,
    title: 'Learn Angular Signals',
    completed: false
  },
  {
    id: 2,
    title: 'Build Task Manager',
    completed: true
  }
];

This is much closer to real application development.

Step 12: Angular 22 Project Structure as the Application Grows

Our project can eventually become:

src/app/
├── core/
│   ├── guards/
│   ├── interceptors/
│   └── services/
│
├── shared/
│   ├── components/
│   ├── directives/
│   └── pipes/
│
├── features/
│   ├── authentication/
│   ├── dashboard/
│   ├── tasks/
│   │   ├── components/
│   │   ├── pages/
│   │   ├── services/
│   │   ├── task.model.ts
│   │   └── task.routes.ts
│   └── settings/
│
├── app.config.ts
├── app.routes.ts
├── app.ts
└── app.html

Don’t create every folder on day one simply because an architecture diagram contains it.

Create structure when the project actually needs it.

Common Mistake #1: One Giant components Folder

Avoid:

components/
├── task-list
├── login
├── dashboard
├── settings
├── profile
└── navbar

These components do not necessarily belong to the same feature.

Prefer:

features/tasks/
features/authentication/
features/dashboard/

Common Mistake #2: Making Everything Shared

A component isn’t shared merely because it could theoretically be reused.

If TaskCard exists only for the Tasks feature, keep it inside:

Move something to shared when genuine cross-feature reuse exists.

Common Mistake #3: Creating Services Without Clear Ownership

Ask:

Is this service application-wide or feature-specific?

For example:

core/services/auth.service.ts

makes sense for global authentication.

But:

features/tasks/services/task.service.ts

is usually a better home for task-specific API logic.

Practical Architecture Rule

Use this decision process:

Is it a business feature?
        ↓
     features/

Used by multiple features?
        ↓
      shared/

Application-wide infrastructure?
        ↓
       core/

Following this rule consistently is what keeps your Angular 22 project structure predictable as the app grows, instead of turning into a folder free-for-all.

Final Angular 22 Project Structure

For our current application:

src/
└── app/
    ├── core/
    ├── features/
    │   └── tasks/
    │       ├── task-list/
    │       └── task.model.ts
    ├── shared/
    ├── app.config.ts
    ├── app.routes.ts
    ├── app.ts
    └── app.html

Key Takeaways

Angular 22 project structure isn’t about creating as many folders as possible.

The goal is to make the codebase predictable.

Remember:

  • main.ts starts the application.
  • app.config.ts contains application-level configuration.
  • app.routes.ts defines top-level routes.
  • features/ contains business functionality.
  • shared/ contains genuinely reusable pieces.
  • core/ contains application-wide infrastructure.
  • Prefer organizing by feature as the application grows.

A clean structure makes future work such as lazy loading, Signals, authentication, API integration and testing significantly easier.

In the next tutorial, we’ll use Angular Signals to turn this Task Manager into a reactive application.

Leave a Reply

Your email address will not be published. Required fields are marked *