npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

runtime-config-loader

v6.1.0

Published

Most applications require certain configuration values that can be changed at runtime of the app. The `environment.ts` files in an Angular application technically work for setting configuration values in an app, but those are buildtime configuration value

Readme

Angular Runtime Configuration Loader

Most applications require certain configuration values that can be changed at runtime of the app. The environment.ts files in an Angular application technically work for setting configuration values in an app, but those are buildtime configuration values. This means that they are set when the application is built, and can't be changed unless the app is built again.

Overview

This library provides an easy way to load one or more JSON files with configuration values or make one or more HTTP GET calls to an API endpoint that returns those values. The config objects that are returned from the call(s) will be combined into a single configuration object. You can then use that configuration throughout the application. The default location of the JSON file is in the assets folder, at ./assets/config.json. When the service loads the file, it stores that configuration object in a local variable which can be accessed via the getConfig() and getConfigObjectKey(key: string) methods. getConfig returns the entire configuration object; getConfigObjectKey(key: string) returns part of the configuration object, namely the part defined by the key passed in. In some cases, the config.json is not finished loading before other modules/services are, so the above methods will return null. If that is the case, subscribe to the configSubject and access the configuration object that way.

How to Implement

In your Angular application's app.config.ts (or wherever you provide your environment providers), use provideRuntimeConfig:

import { provideRuntimeConfig } from 'runtime-config-loader';

export const appConfig: ApplicationConfig = {
	providers: [
		// ...,
		provideRuntimeConfig({ configUrl: './assets/config.json' }),
		// ...
	],
};

That's it; it's that simple. The provideRuntimeConfig function sets up the APP_INITIALIZER token to load the configuration from a file or an API endpoint before the application starts.

Type Safety with Generics

There are two main ways to use generics for type safety in your application.

Option 1: Using the RUNTIME_CONFIG Token (Recommended)

You can provide the type directly in provideRuntimeConfig. This also sets up the RUNTIME_CONFIG injection token, which you can use to inject the typed configuration object directly into your components or services.

// app.config.ts
provideRuntimeConfig<MyConfig>({ configUrl: './assets/config.json' })

// component.ts
import { RUNTIME_CONFIG } from 'runtime-config-loader';

constructor(@Inject(RUNTIME_CONFIG) private config: MyConfig) {
	console.log(this.config.apiUrl); // Fully typed!
}

Option 2: Using the Service with a Type Alias

If you prefer to use the RuntimeConfigLoaderService methods (like getConfigObjectKey), you can define a type alias to avoid repeating the generic type everywhere.

// config.service.ts
export type MyConfigService = RuntimeConfigLoaderService<MyConfig>;

// component.ts
constructor(private configSvc: MyConfigService) {
	const apiUrl = this.configSvc.getConfigObjectKey('apiUrl'); // Typed as string | null
}

Option 3: Specific Configuration Tokens

If you prefer your components to depend only on specific configuration values rather than the entire configuration object, you can use the provideConfigToken helper. This allows you to inject individual configuration properties cleanly and maintain strict boundaries.

import { InjectionToken } from '@angular/core';
import { provideRuntimeConfig, provideConfigToken } from 'runtime-config-loader';

// 1. Define tokens for your specific configuration values
export const API_URL = new InjectionToken<string>('API_URL');

// 2. Provide them using the helper
export const appConfig: ApplicationConfig = {
	providers: [
		provideRuntimeConfig<MyConfig>({ configUrl: './assets/config.json' }),

		// Provide the specific token mapping it to a key in your config
		provideConfigToken(API_URL, 'apiUrl'),

		// It also supports dot-notation for nested keys
		// provideConfigToken(NESTED_TOKEN, 'api.baseUrl')
	],
};

// 3. Inject them directly
// component.ts
constructor(@Inject(API_URL) private apiUrl: string) {
	console.log(this.apiUrl); // Typed as string | null
}

Nested Key Access (Dot-Notation)

The getConfigObjectKey method supports dot-notation for accessing deeply nested configuration values.

// For a config like: { api: { baseUrl: 'https://api.com' } }
const baseUrl = this.configSvc.getConfigObjectKey('api.baseUrl'); // Returns 'https://api.com'

[!NOTE] When using dot-notation for nested keys, the return type will be any unless you provide an explicit generic type to the call: this.configSvc.getConfigObjectKey<string>('api.baseUrl')

Configuration

The provideRuntimeConfig function accepts a configuration object with a configUrl property. This can be a single string or an array of strings.

Single Config File

The default location is ./assets/config.json. If you'd like to load the file from a different location:

provideRuntimeConfig({ configUrl: './path/to/config/config.json' });

Multiple Config Files

You can load multiple files (or API endpoints) and they will be merged into a single configuration object.

provideRuntimeConfig({
	configUrl: [
		'./path/to/config/config-1.json',
		'./path/to/config/config-2.json',
	],
});

If an attribute is repeated in multiple configuration files, the latest value is kept. For example, if apiUrl exists in both files above, the value from config-2.json will override the value from config-1.json.

Fallback Configuration

If you'd like the application to gracefully fall back to a default configuration in the event that the config file(s) fail to load (e.g., due to network errors or 404s), you can provide a defaultConfig object.

provideRuntimeConfig({
	configUrl: './assets/config.json',
	defaultConfig: {
		apiUrl: 'https://fallback.api.com',
		theme: 'light',
	},
});

When a failure occurs and defaultConfig is provided, the application will emit a console warning (Falling back to default configuration), load the provided object, and proceed with initialization.

HTTP Options and Headers

You can pass standard Angular HttpClient options (such as custom HttpHeaders or HttpContext) to the underlying HTTP request doing the fetching.

Pass an options object into the provideRuntimeConfig function:

import { HttpHeaders } from '@angular/common/http';

provideRuntimeConfig({
	configUrl: './assets/config.json',
	options: {
		headers: new HttpHeaders({
			Authorization: 'Bearer YOUR_TOKEN_HERE',
			'X-Custom-Header': 'custom-value',
		}),
		withCredentials: true,
	},
});

This is useful for APIs that require authentication or tracking headers to return configuration data.

Runtime Schema Validation

You can provide an optional validator function to verify the configuration before the application starts. If validation fails (returns false, throws an error, or emits an error), the configuration will be set to null.

The validator supports synchronous results, Promise<boolean>, and Observable<boolean>.

provideRuntimeConfig<MyConfig>({
	configUrl: './assets/config.json',
	validator: (config) => {
		return !!config.apiUrl && !!config.apiKey;
	},
});

Integration with Zod

This feature integrates well with schema validation libraries like Zod:

import { z } from 'zod';

const ConfigSchema = z.object({
	apiUrl: z.string().url(),
	apiKey: z.string().min(10),
});

provideRuntimeConfig({
	configUrl: './assets/config.json',
	validator: (config) => ConfigSchema.safeParse(config).success,
});

Make sure that the path(s) you provide are accessible by the Angular application. The assets folder is generally the easiest place to serve these files.

Testing

When writing unit tests for components or services that depend on RUNTIME_CONFIG or RuntimeConfigLoaderService, you can easily mock the configuration using the provideMockRuntimeConfig utility.

This avoids making HTTP requests and allows you to instantly return a mocked configuration object of your choosing.

import { TestBed } from '@angular/core/testing';
import {
	provideMockRuntimeConfig,
	RUNTIME_CONFIG,
	RuntimeConfigLoaderService,
} from 'runtime-config-loader';

describe('MyComponent', () => {
	beforeEach(() => {
		TestBed.configureTestingModule({
			providers: [
				// Provide the mock configuration object
				provideMockRuntimeConfig({
					apiUrl: 'https://mock-api.com',
					theme: 'dark',
				}),
			],
		});
	});

	it('should use the mocked config', () => {
		const config = TestBed.inject(RUNTIME_CONFIG);
		expect(config.apiUrl).toBe('https://mock-api.com');

		// If testing something that uses the service directly:
		const service = TestBed.inject(RuntimeConfigLoaderService);
		expect(service.getConfigObjectKey('theme')).toBe('dark');
	});
});