Angular Project Structure
Read one Angular interview question at a time, then flip for the complete explanation, example, and code.
Read one Angular interview question at a time, then flip for the complete explanation, example, and code.
Angular Interview Questions · Angular Project Structure Companion Article
An Angular project contains application source code, configuration files, dependencies, static files, build settings, and environment-specific configuration. Understanding where these files are located and why Angular uses them makes development, debugging, deployment, and team collaboration much easier. A developer should not think of the Angular project structure as just a collection of folders: each important file participates in a particular stage of the application lifecycle, from installing dependencies and loading build configuration to bootstrapping the application and rendering it in the browser.
For example:
package.json
↓
Dependencies installed
↓
angular.json
↓
Build configuration loaded
↓
main.ts
↓
Angular application bootstrapped
↓
Application configuration loaded
↓
Root component rendered
↓
index.html displays the application
An Angular workspace is the top-level directory in which Angular applications and libraries are developed.
When you create a project using:
ng new my-app
Angular CLI creates a workspace and normally creates the first Angular application inside that workspace.
A simplified workspace may look like this:
my-app/
├── public/
├── src/
│ ├── app/
│ ├── index.html
│ ├── main.ts
│ └── styles.css
├── angular.json
├── package.json
├── package-lock.json
├── tsconfig.json
├── tsconfig.app.json
└── node_modules/
The workspace contains two major categories of files.
These contain the actual application code.
Examples:
src/
src/app/
src/main.ts
src/index.html
src/styles.css
These control dependencies, compilation, builds, testing, and Angular CLI behavior.
Examples:
angular.json
package.json
tsconfig.json
A workspace can contain a single Angular application or multiple applications and libraries.
For larger organizations, one workspace may contain:
projects/
├── admin-portal/
├── customer-portal/
└── shared-ui/
This approach is useful when multiple Angular projects need to share common configuration or reusable libraries.
The src directory contains the source files used to build the Angular application.
A typical structure is:
src/
├── app/
├── index.html
├── main.ts
└── styles.css
The app directory contains most of the Angular-specific application code.
As an application grows, developers usually organize the app folder according to features or responsibilities.
For example:
src/app/
├── core/
├── shared/
├── features/
│ ├── products/
│ ├── orders/
│ └── users/
├── app.config.ts
├── app.routes.ts
└── root-component-files
There is no requirement that every application use exactly this organization. The best structure depends on the size and architecture of the application.
For a small application, keeping a few components directly under app/ may be reasonable.
For a large business application, grouping files by feature usually makes maintenance easier.
For example:
features/
└── products/
├── components/
├── services/
├── models/
└── product.routes.ts
This keeps product-related functionality together instead of scattering it across the entire project.
main.ts is the main entry point of an Angular application.
It is one of the first application source files involved when Angular starts.
In a modern standalone Angular application, it commonly bootstraps the root application using bootstrapApplication().
Example:
import { bootstrapApplication } from '@angular/platform-browser';
import { App } from './app/app';
import { appConfig } from './app/app.config';
bootstrapApplication(App, appConfig)
.catch(error => console.error(error));
The basic startup flow is:
Browser loads application
↓
main.ts executes
↓
bootstrapApplication() runs
↓
Application configuration is loaded
↓
Root component is created
↓
Angular renders the UI
It acts as the bridge between the browser-loaded JavaScript application and Angular.
Developers normally keep this file small.
Business logic should generally not be placed inside main.ts.
Instead, its primary responsibility should be application startup.
index.html is the main HTML document used to host the Angular application.
A simplified version may look like:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Angular App</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<app-root></app-root>
</body>
</html>
The important part is the root element:
<app-root></app-root>
Angular finds the root component associated with this selector and renders the application inside it.
In a traditional website, different URLs may load completely different HTML files.
An Angular Single Page Application generally starts with one main HTML document and changes the displayed views using Angular components and routing.
For example:
/index.html
↓
Angular starts
↓
/home
/products
/products/25
/cart
/profile
These routes can display different Angular components without requiring a completely separate HTML document for every view.
Normally, no.
The Angular build process handles the generated JavaScript and stylesheet bundles for the application.
Developers therefore usually do not manually add generated Angular bundle files using <script> tags inside index.html.
Angular applications commonly contain:
<base href="/">
The base URL helps Angular and the browser resolve relative URLs.
It becomes particularly important when the application uses Angular Router.
If an application is deployed under a subdirectory such as:
https://example.com/customer/
the deployment configuration may need to account for that base path.
Incorrect base URL configuration can lead to problems such as:
Page refresh returns 404
Assets fail to load
Router links behave incorrectly
Deployment URL configuration should therefore be tested separately from local development.
styles.css contains styles that apply globally across the application.
Example:
html,
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
}
body {
background: #f5f5f5;
}
Global styles are suitable for things such as:
Angular components can also have their own styles.
Conceptually:
styles.css
↓
Application-wide styles
Component stylesheet
↓
Styles related to a specific component
Suppose an application contains a reusable product card.
General page typography may belong in:
src/styles.css
Product-card-specific styling should normally stay with the product card component.
This prevents one large stylesheet from becoming responsible for every visual element in the application.
angular.json is one of the most important configuration files in an Angular CLI workspace.
It defines workspace-level and project-level settings used by Angular development and build tools.
A simplified structure looks like:
{
"version": 1,
"projects": {
"my-app": {
"projectType": "application",
"sourceRoot": "src",
"architect": {
"build": {},
"serve": {},
"test": {}
}
}
}
}
The actual generated file contains additional configuration.
It can define settings related to:
For example, Angular may have different build settings for:
development
production
staging
Angular CLI commands often correspond to configured targets.
For example:
ng build
uses the application's build target.
ng serve
uses the application's development-server configuration.
Conceptually:
Angular CLI command
↓
angular.json
↓
Target configuration
↓
Angular builder
↓
Task executed
This is why changing certain values inside angular.json can affect how ng build or ng serve behaves.
Applications frequently need different build behavior in development and production.
Development may prioritize:
Debugging
Readable stack traces
Source maps
Fast rebuilds
Production may prioritize:
Optimized bundles
Smaller output
Performance
Deployment readiness
Angular allows named configurations to be defined for build targets.
A configuration can then be selected using a command such as:
ng build --configuration production
Custom configurations can also be created when necessary.
For example:
ng build --configuration staging
This is useful when an organization has separate development, testing, staging, and production systems.
package.json describes the Node/npm side of the Angular workspace.
It contains information about packages required by the project.
A simplified example is:
{
"scripts": {
"start": "ng serve",
"build": "ng build",
"test": "ng test"
},
"dependencies": {
"@angular/core": "...",
"@angular/common": "...",
"@angular/router": "..."
},
"devDependencies": {
"@angular/cli": "...",
"typescript": "..."
}
}
Packages required by the application are listed as dependencies.
Examples can include:
@angular/core
@angular/common
@angular/router
Development-related packages may appear under devDependencies.
Examples include tooling used during:
Compilation
Development
Testing
Building
The scripts section provides convenient commands.
For example:
"scripts": {
"start": "ng serve",
"build": "ng build"
}
You can then execute:
npm start
instead of manually typing:
ng serve
These files have different responsibilities.
Describes which dependencies the project requires.
Example:
"dependencies": {
"@angular/core": "^22.0.0"
}
Records the dependency tree and resolved package versions installed by npm.
It helps developers and deployment systems reproduce consistent installations.
A common mistake is treating package-lock.json as an unnecessary temporary file.
For npm-based projects, it is generally kept in version control.
After running:
npm install
npm installs packages into:
node_modules/
This directory may become very large because Angular itself and its tooling depend on many npm packages.
Developers normally do not manually edit files inside node_modules.
They also normally do not commit the entire directory to Git.
Instead, another developer can restore the dependencies using:
npm install
based on the dependency information stored in the project's npm configuration files.
Angular applications are primarily written using TypeScript.
tsconfig.json provides the base TypeScript configuration used within the workspace.
A simplified example could contain:
{
"compilerOptions": {
"strict": true,
"target": "ES2022"
}
}
The exact configuration depends on the Angular and TypeScript versions used by the project.
Examples include:
Angular projects may also contain additional TypeScript configuration files such as:
tsconfig.app.json
tsconfig.spec.json
These files serve different compilation contexts.
Conceptually:
tsconfig.json
↓
Base TypeScript configuration
↓
┌───────────────┬─────────────────┐
↓ ↓
tsconfig.app.json tsconfig.spec.json
Application code Test code
This separation allows different TypeScript settings to be applied where necessary.
Angular also has compiler-specific options.
These can appear under:
"angularCompilerOptions": {
}
Angular compiler configuration is different from normal TypeScript compiler configuration.
Conceptually:
compilerOptions
↓
TypeScript compiler behavior
angularCompilerOptions
↓
Angular-specific compilation behavior
This distinction becomes useful when investigating template type checking or Angular compilation problems.
Modern Angular applications commonly use standalone APIs.
In a standalone application, app.config.ts can contain application-wide providers.
Example:
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes)
]
};
This configuration is then passed when the application starts.
Example:
bootstrapApplication(App, appConfig);
Depending on application requirements, global providers may configure functionality such as:
Routing
HTTP services
Animations
Application initialization
Dependency injection providers
Error handling
Other application-wide services
The idea is to keep application-wide setup in a predictable location instead of spreading startup configuration throughout unrelated components.
These files may both contain "configuration," but their purposes are very different.
| File | Main Responsibility |
|---|---|
app.config.ts | Runtime Angular application providers and setup |
angular.json | Angular CLI, build, serve, test, assets, and workspace configuration |
For example:
Configuring Angular Router belongs to application configuration.
provideRouter(routes)
Configuring build output or global styles belongs to workspace/build configuration.
"styles": [
"src/styles.css"
]
Remember this distinction:
app.config.ts
= How the Angular application is assembled
angular.json
= How Angular tooling builds and manages the project
Modern Angular development commonly uses standalone APIs.
However, developers may still encounter existing applications based on Angular modules.
A standalone application may contain:
app.config.ts
app.routes.ts
An older or intentionally module-based application may contain:
app.module.ts
app-routing.module.ts
Therefore, finding app.module.ts in an Angular codebase does not automatically mean that the application is incorrect.
It usually means the project follows the NgModule architecture rather than the newer standalone approach.
This distinction is particularly important when joining an existing enterprise Angular project.
Applications commonly need files that should be served without being processed as normal TypeScript application source.
Examples include:
Images
Icons
JSON files
Documents
Static text files
Fonts
Robots files
Other static resources
Current Angular CLI projects provide a top-level:
public/
directory for static files.
For example:
public/
├── images/
│ └── logo.png
├── documents/
│ └── help.pdf
└── config/
└── information.json
A file placed under the configured static asset directory can be copied to the build output without being treated like application TypeScript code.
Developers working with different Angular versions may see different conventions.
Modern Angular CLI projects use:
public/
as the default static public directory.
Many existing Angular projects use:
src/assets/
and configure that location through angular.json.
Both patterns may therefore appear in real projects.
The important concept is not just the folder name. The important concept is understanding which folders are configured as build assets.
Angular build configuration can define which files and directories should be copied into the generated application.
This is especially useful when maintaining projects created with older Angular versions.
Static asset locations are suitable for content such as:
logo.png
background.jpg
sample-data.json
manual.pdf
icons/
They are not normally the correct place for Angular components or TypeScript business logic.
For example:
public/images/product.png
is appropriate.
But:
public/product.service.ts
is not a sensible Angular application structure.
Application TypeScript code belongs under the Angular source structure.
Applications often connect to different systems depending on where they are running.
For example:
Development API
Testing API
Staging API
Production API
Hard-coding those URLs throughout components creates maintenance problems.
Instead, Angular supports environment-specific build configuration.
Environment files can be generated using:
ng generate environments
A project may then contain:
src/environments/
├── environment.ts
├── environment.development.ts
└── environment.staging.ts
Example production-oriented configuration:
export const environment = {
production: true,
apiUrl: 'https://api.example.com'
};
Development configuration:
export const environment = {
production: false,
apiUrl: 'http://localhost:8080'
};
Application code can import the environment configuration:
import { environment } from '../environments/environment';
console.log(environment.apiUrl);
Build configuration can determine which environment-specific file is used.
Angular can use fileReplacements for environment-specific builds.
Conceptually:
environment.ts
↓
Development build
↓
environment.development.ts used
environment.ts
↓
Production build
↓
Production configuration used
A development build might be executed with:
ng build --configuration development
A staging build could use:
ng build --configuration staging
This allows application source code to continue importing a consistent environment location while Angular substitutes the correct configuration during the build.
Environment files are useful for configuration, but they should not be treated as secure secret storage.
Do not place sensitive secrets such as:
Database passwords
Private encryption keys
Service-account credentials
Server secrets
Private API credentials
inside Angular client-side source files.
Angular executes in the user's browser. Values bundled into browser JavaScript can potentially be inspected by users.
For example, this is unsafe:
export const environment = {
databasePassword: 'my-secret-password'
};
A real secret should remain on a trusted backend or another appropriate secure system.
A frontend application should call the backend, and the backend should use protected credentials where required.
Think of Angular environment values as build-time client configuration, not a secret vault.
Consider what happens when a developer executes:
npm start
A simplified process is:
1. package.json
Finds the "start" script
2. Angular CLI
Executes the configured serve command
3. angular.json
Provides project and development-server settings
4. TypeScript configuration
Controls TypeScript compilation
5. main.ts
Starts the Angular application
6. app.config.ts
Provides application-wide configuration
7. Root component
Creates the application's first Angular view
8. index.html
Provides the browser document that hosts the application
9. styles.css
Provides global application styles
10. public/
Provides static resources
Understanding this relationship is more useful than memorizing individual filenames.
A useful way to understand Angular project structure is to divide files according to their responsibility.
package.json
angular.json
tsconfig.json
tsconfig.app.json
These mainly influence dependency management, compilation, Angular CLI behavior, or builds.
src/main.ts
src/app/app.config.ts
These participate in starting and configuring the Angular application.
src/index.html
src/styles.css
src/app/
public/
These provide the host page, styling, components, templates, services, and static files.
This mental model makes unfamiliar Angular projects much easier to understand.
Suppose an application needs a company logo.
Place the image in a configured static location such as:
public/images/company-logo.png
Then reference the public path from the application:
<img src="/images/company-logo.png" alt="Company logo">
The image does not need to become a TypeScript component because it is simply a static resource.
Suppose every page should use the same box sizing.
Add the rule to:
src/styles.css
Example:
* {
box-sizing: border-box;
}
A style that belongs only to one feature component should usually stay with that component instead of being added globally.
Suppose developers use:
http://localhost:8080
while the deployed application uses:
https://api.example.com
Instead of writing URLs directly inside every service, configure the appropriate environment values and use them from the service.
This makes deployment configuration easier to maintain.
A small demonstration application may work with one component, but production applications quickly become difficult to maintain when routing, HTTP calls, UI logic, forms, and business rules all exist in the same file.
Separate functionality according to responsibility.
Changes made directly inside:
node_modules/
can disappear after dependencies are reinstalled.
Application code should not depend on manually modified installed packages.
Avoid repeatedly writing:
const url = 'http://localhost:8080/api/users';
throughout services.
Use centralized configuration where appropriate.
Anything delivered to the browser should be considered accessible to the client.
Do not assume that naming a variable secretKey or placing it in an environment file makes it private.
Placing every CSS rule in styles.css can eventually create:
Naming conflicts
Unexpected overrides
Large global stylesheets
Difficult maintenance
Use global styles for genuinely global concerns and component styles for feature-specific presentation.
Incorrect configuration can affect:
ng serve
ng build
assets
styles
production builds
deployment output
When changing workspace configuration, understand which project and target the setting belongs to.
Angular projects differ depending on:
Angular version
Standalone vs NgModule architecture
Single-project vs multi-project workspace
Testing setup
SSR requirements
Organization architecture
Custom build configuration
Therefore, developers should understand the purpose of the files instead of memorizing one exact directory tree.
When joining an existing Angular project, inspect it in a logical order.
Understand:
Angular version
Major dependencies
Available npm scripts
Development tools
Understand:
Project names
Build configuration
Serve configuration
Assets
Styles
Output configuration
Environment-specific builds
Identify how the application is bootstrapped.
Look for:
app.config.ts
or, in module-based applications:
app.module.ts
This helps identify the architectural style.
Look for files such as:
app.routes.ts
This reveals the major application navigation structure.
Finally, move into actual application features such as:
users/
products/
orders/
dashboard/
authentication/
This approach is much faster than opening files randomly.
A maintainable business application may gradually evolve toward a structure similar to:
src/
└── app/
├── core/
│ ├── guards/
│ ├── interceptors/
│ └── services/
├── shared/
│ ├── components/
│ ├── directives/
│ └── pipes/
├── features/
│ ├── authentication/
│ ├── dashboard/
│ ├── products/
│ └── orders/
├── app.config.ts
└── app.routes.ts
This is an organizational strategy rather than a requirement imposed on every Angular application.
Often contains application-wide infrastructure.
Examples:
Authentication services
HTTP interceptors
Route guards
Global services
Often contains reusable UI or utility functionality.
Examples:
Buttons
Loading indicators
Reusable pipes
Reusable directives
Common components
Contains business functionality.
Examples:
Products
Orders
Customers
Payments
Reports
Feature-oriented organization becomes particularly valuable when multiple developers work on a large application.
| File or Folder | Responsibility |
|---|---|
src/ | Main application source |
main.ts | Starts the Angular application |
index.html | Browser host document |
styles.css | Global styles |
app.config.ts | Application-wide providers and runtime setup |
angular.json | Angular CLI and workspace/build configuration |
package.json | npm dependencies and scripts |
package-lock.json | Resolved npm dependency versions |
tsconfig.json | Base TypeScript configuration |
tsconfig.app.json | Application-specific TypeScript configuration |
public/ | Static public files |
src/environments/ | Environment-specific client configuration when configured |
node_modules/ | Installed npm packages |
Instead of memorizing filenames independently, associate each file with one question.
Where is my application code?
→ src/
Where does Angular start?
→ main.ts
Which HTML page hosts the application?
→ index.html
Where are global styles?
→ styles.css
Where are application-wide Angular providers configured?
→ app.config.ts
How is the Angular workspace built and served?
→ angular.json
Which npm packages does the project need?
→ package.json
How should TypeScript compile the project?
→ tsconfig.json
Where should public static files go?
→ public/
How can build-specific client settings be handled?
→ environment configuration
Once these relationships are clear, navigating even a large Angular codebase becomes much easier.
Angular project structure separates different responsibilities deliberately. Application logic belongs mainly under src/app, startup happens through main.ts, browser hosting begins with index.html, global styling belongs in styles.css, dependencies are managed through package.json, TypeScript behavior is controlled through TypeScript configuration, and Angular CLI build behavior is controlled through angular.json.
Modern Angular applications also separate application-level provider configuration through files such as app.config.ts, while static resources can be served through public/. Environment-specific build configuration can be used when development, staging, and production systems require different client settings.
The most useful skill is therefore not memorizing every generated filename. It is understanding which layer owns which responsibility and knowing where to investigate when something goes wrong.