Production Build
ng build turns your Angular app into small, optimised static files. A few settings — environments, base href, budgets and a server fallback — make sure it works the same in production as on your machine.
On this page · 6 min · Advanced
On this page
- Learning objectives
- Explanation
- Syntax
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 6 min
- Difficulty
- Advanced
- Updated
- Oct 28, 2026
Related tutorials
Learning objectives#
- Create a production build and know its output
- Use environment files for configuration
- Set base href and budgets
- Deploy to static hosting with route fallback
Explanation#
ng build uses the production configuration by default: ahead-of-time compilation, tree-shaking, minification, hashed file names. Output: dist/<project>/browser.
Environment files: generate with ng g environments; angular.json fileReplacements swaps environment.ts for environment.development.ts in dev builds. Put the API URL and feature flags there — never secrets.
Serving from a sub-folder? Build with ng build --base-href /shop/ so asset and route URLs are correct.
Budgets in angular.json warn or fail the build when the initial bundle grows past a limit — a guard against accidental huge dependencies.
Any static host works (Hostinger, Azure Static Web Apps, Netlify, S3 + CloudFront). Configure a fallback so every unknown path serves index.html, or deep links like /products/7 return 404.
Need SEO-friendly HTML or faster first paint? Angular SSR/prerendering (ng add @angular/ssr) renders pages on the server.
Syntax#
ng build # production by default → dist/shop-app/browser
ng build --base-href /shop/ # when hosted in a sub-folder
npx http-server dist/shop-app/browser -p 8080 # quick local check
Code example: Environments and a production-safe API URL#
// src/environments/environment.ts (used by ng build — production)
export const environment = {
production: true,
apiUrl: 'https://api.shop.example.com',
featureNewCheckout: false,
};
// src/environments/environment.development.ts (swapped in by angular.json for ng serve)
// export const environment = { production: false, apiUrl: '/api', featureNewCheckout: true };
// src/app/app.config.ts
import { ApplicationConfig, InjectionToken } from '@angular/core';
import { provideHttpClient, withFetch } from '@angular/common/http';
export const API_URL = new InjectionToken<string>('API_URL');
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withFetch()),
{ provide: API_URL, useValue: environment.apiUrl },
],
};
/* angular.json (excerpt)
"budgets": [
{ "type": "initial", "maximumWarning": "500kB", "maximumError": "1MB" },
{ "type": "anyComponentStyle", "maximumWarning": "4kB", "maximumError": "8kB" }
]
public_html/.htaccess (Apache / Hostinger) — route fallback
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [L]
*/
ng build prints the initial and lazy chunks with sizes, e.g. “main-AB12CD.js 210 kB | Estimated transfer 62 kB” and “Lazy chunk files: chunk-EF34.js (products) 34 kB”, and fails if a budget’s error limit is exceeded. Uploading dist/shop-app/browser plus the .htaccess file makes deep links like /products/7 work.
This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.
Step-by-step explanation#
- environment.ts holds production settings; the development file replaces it for ng serve.
- The API URL is provided through an InjectionToken, so services do not hard-code it.
- Budgets stop the build when bundles grow beyond agreed limits.
- The output to deploy is the browser folder inside dist.
- The .htaccess rules send unknown paths to index.html so the router can handle them.
Real-world use case#
A team deploys the same build artefact to staging and production on Azure Static Web Apps; a staticwebapp.config.json navigationFallback replaces .htaccess, and environment-specific API URLs come from the build configuration.
Common mistakes#
Everything in the bundle is public. Keep secrets on the server.
Upload the contents of dist/<project>/browser, not the dist folder itself.
Static hosts look for real files. Configure the index.html fallback.
Best practices#
- Build once, configure per environment
- Keep budgets tight
- Set base href for sub-folders
- Configure route fallback on the host
Remember this#
ng build → dist/<project>/browser.
environment files = public config only.
Static hosting needs an index.html fallback.
Practice exercise#
Your task: Write the command to build for a site served at https://example.com/portal/ and the matching Apache fallback rule.
Need a hint?
Show solution
ng build --base-href /portal/
# public_html/portal/.htaccess
# RewriteEngine On
# RewriteBase /portal/
# RewriteCond %{REQUEST_FILENAME} !-f
# RewriteCond %{REQUEST_FILENAME} !-d
# RewriteRule ^ /portal/index.html [L]
Mini quiz#
Which folder do you upload after ng build in Angular 17+?
Want more? Practise all Angular MCQs · Angular interview questions
My notes#
Saved in this browser.