tyfigo

Getting started

Install tyfigo, register the content mapper and import your first config file.

Install

tyfigo needs TypeScript 7.1, the first release with content mappers.

npm i tyfigo
npm i -D typescript@7.1.0-beta

tyfigo is a run-time dependency: the module a config import turns into reads .env files and the environment when your app starts.

Register the content mapper

Add tyfigo to contentMappers in tsconfig.json, with every suffix you want it to own, and include the folder your config files live in:

tsconfig.json
{
	"compilerOptions": {
		"module": "nodenext",
		"strict": true,
		"noEmit": true,
		"allowImportingTsExtensions": true,
		"skipLibCheck": true,
		"types": ["node"],
	},
	"contentMappers": [
		{
			"package": "tyfigo",
			"extensions": [
				".config.yaml",
				".config.yml",
				".config.toml",
				".config.jsonc",
				".config.json5",
				".config.ini",
				".config.properties",
				".config.xml",
			],
		},
	],
	"include": ["src", "config"],
}

Keep this list as it is unless you keep config files in a .config/ folder (.config/app.yaml). That layout needs the plain extensions too (.yaml, .toml, …), which makes tyfigo the owner of every file with them; see A .config directory before you add them.

Including config makes tsc check environment and local files even when no code imports them directly. TypeScript 7 defaults types to [], so list node (or bun) yourself. skipLibCheck keeps tsc from checking the bundler types that the plugin declarations reference, which you only have installed for the bundler you use.

Type-check with --runExternalCode

tsc runs content mappers only when you pass --runExternalCode:

package.json
{
	"scripts": {
		"typecheck": "tsc --noEmit --runExternalCode"
	}
}

Without the flag, tsc can't resolve config imports:

src/main.ts(1,20): error TS2307: Cannot find module '../config/app.config.yaml' or its corresponding type declarations.
tsconfig.json(10,2): error TS18068: Content mappers require the '--runExternalCode' command line flag to be enabled.

Write a config file

config/app.config.yaml
name: tyfigo-node-example
server:
  host: localhost
  port: ${PORT:-3000}
database:
  url: ${DATABASE_URL}
  pool:
    min: 1
    max: 5
features: [search]
config/app.production.config.yaml
server:
  host: 0.0.0.0
database:
  pool:
    max: 20
features: [search, billing]
.env
DATABASE_URL=postgres://localhost:5432/app
PORT=8080

Import it

src/main.ts
import config from '../config/app.config.yaml';

console.log(config.server.port);

The type of config comes from app.config.yaml:

// const config: {
//   readonly name: string;
//   readonly server: { readonly host: string; readonly port: number };
//   readonly database: { readonly url: string; readonly pool: { readonly min: number; readonly max: number } };
//   readonly features: readonly string[];
// }

Run it

Load tyfigo where your code runs so the import works at run time too. On Node 24:

NODE_ENV=production node --import tyfigo/register src/main.ts

With NODE_ENV=production the value is { name: 'tyfigo-node-example', server: { host: '0.0.0.0', port: 8080 }, … }. For other runtimes and bundlers, see Node, Bun, Vite and the rest of the sidebar.

Editor support

Content mappers run in the TypeScript 7 language server. In VS Code or Cursor, install the TypeScript (Native Preview) extension (TypeScriptTeam.native-preview) and point it at your project's TypeScript, since the extension may bundle an older version:

.vscode/settings.json
{
	"js/ts.experimental.useTsgo": true,
	"js/ts.tsdk.path": "./node_modules/typescript",
}

Editors run content mappers only in a trusted workspace. Trust the workspace, and allow the extension to use the workspace version of TypeScript when it asks. Hover, go to definition and errors then work across the config file and your code.

On this page