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

@stitchem/config

v1.0.0

Published

Type-safe configuration management for Stitchem. Loads values from `.env` files, merges multiple sources, validates with your schema library of choice, and exposes everything through a fully-typed DI service.

Downloads

1,861

Readme

@stitchem/config

Type-safe configuration management for Stitchem. Loads values from .env files, merges multiple sources, validates with your schema library of choice, and exposes everything through a fully-typed DI service.

Install

npm install @stitchem/config
# or
pnpm add @stitchem/config

Peer dependencies: @stitchem/core

Setup

Define named config namespaces, then load them in ConfigModule.forRoot:

import { ConfigModule, ConfigService, defineConfig, envSource } from '@stitchem/config';
import { module } from '@stitchem/core';

const databaseConfig = defineConfig('database', (storage) => ({
  host: storage.get<string>('DB_HOST') ?? 'localhost',
  port: Number(storage.get('DB_PORT') ?? 5432),
}));

@module({
  imports: [
    ConfigModule.forRoot({
      sources: [envSource({ path: '.env' })],
      load: [databaseConfig],
    }),
  ],
})
class AppModule {}

Augment the Registry

Extend ConfigRegistry to enable typed path access across your app:

// config.d.ts
declare module '@stitchem/config' {
  interface ConfigRegistry {
    database: { host: string; port: number };
  }
}

ConfigService.get() will now autocomplete and type-check all paths:

config.get('database')       // { host: string; port: number }
config.get('database.host')  // string
config.get('database.port')  // number

Schema Validation

Pass any Standard Schema-compatible library as the third argument to defineConfig. Zod, Valibot, ArkType, and Effect Schema all work:

import { z } from 'zod';

const serverConfig = defineConfig(
  'server',
  (storage) => ({
    host: storage.get('HOST'),
    port: storage.get('PORT'),
  }),
  z.object({
    host: z.string().default('0.0.0.0'),
    port: z.coerce.number().min(1).max(65535).default(3000),
  })
);

Validation errors throw a ConfigError with structured issues.

Multiple Sources

Sources are deep-merged in order — later sources override earlier ones:

ConfigModule.forRoot({
  sources: [
    envSource({ path: '.env' }),
    envSource({ path: '.env.local', required: false }),
  ],
  load: [serverConfig, databaseConfig],
})

Variable expansion (${VAR}) is enabled by default in EnvSource.

Feature Modules

Use forFeature to register config namespaces alongside the feature module that needs them:

const redisConfig = defineConfig('redis', (storage) => ({
  url: storage.get<string>('REDIS_URL') ?? 'redis://localhost',
}));

@module({
  imports: [ConfigModule.forFeature(redisConfig)],
  providers: [CacheService],
})
class CacheModule {}

Feature namespaces are initialized after the root module and become available via ConfigService.get('redis').

Accessing Config

Inject ConfigService anywhere in the DI container:

@injectable()
class AppService {
  static inject = [ConfigService] as const;

  constructor(private config: ConfigService) {}

  start() {
    const host = this.config.get('database.host');
    const port = this.config.get('database.port');
    console.log(`Connecting to ${host}:${port}`);
  }
}

API Reference

| Export | Description | |--------|-------------| | ConfigModule | DI module — forRoot(options) and forFeature(...configs) | | ConfigService | Injectable — get(path), getNamespace(name), hasNamespace(name) | | defineConfig(name, loader, schema?) | Create a typed namespace definition | | EnvSource / envSource(options?) | Load values from a .env file | | ConfigStorage | Internal injectable; receive it in namespace loaders | | ConfigError | Error class with code and context fields | | ConfigRegistry | Augmentable interface to type config paths | | ConfigPath | Union of all valid dot-notation paths (from ConfigRegistry) | | InferConfig<T> | Extract the output type of a ConfigNamespaceDefinition | | ConfigSource | Interface for custom config sources | | CONFIG_OPTIONS | Injection token for module options |

License

MIT