Skip to content

Multiple Formats

bunfig supports a wide variety of configuration file formats, making it flexible and compatible with different project setups and preferences.

Supported Formats

bunfig supports the following configuration file formats:

  • TypeScript (.ts, .mts, .cts)
  • JavaScript (.js, .mjs, .cjs)
  • JSON (.json)

All formats support both default exports and named exports, giving you flexibility in how you structure your configuration files.

Format Priority

When multiple configuration files exist with the same base name, bunfig follows this priority order:

  1. TypeScript files (.ts, .mts, .cts)
  2. JavaScript files (.js, .mjs, .cjs)
  3. JSON files (.json)

Within each category, the order is:

  • .ts > .mts > .cts
  • .js > .mjs > .cjs

TypeScript Configuration

Default Export

ts
// my-app.config.ts
export default {
  port: 3000,
  host: 'localhost',
  database: {
    url: 'postgresql://localhost:5432/myapp',
    pool: 10,
  },
  features: ['auth', 'logging'],
}

Named Export

ts
// my-app.config.ts
export const config = {
  port: 3000,
  host: 'localhost',
  database: {
    url: 'postgresql://localhost:5432/myapp',
    pool: 10,
  },
}

With Type Definitions

ts
// my-app.config.ts
interface AppConfig {
  port: number
  host: string
  database: {
    url: string
    pool: number
  }
  features?: string[]
}

const config: AppConfig = {
  port: 3000,
  host: 'localhost',
  database: {
    url: 'postgresql://localhost:5432/myapp',
    pool: 10,
  },
  features: ['auth', 'logging'],
}

export default config

Dynamic Configuration

ts
// my-app.config.ts
export default {
  port: Number(process.env.PORT) || 3000,
  host: process.env.HOST || 'localhost',
  database: {
    url: process.env.DATABASE_URL || 'postgresql://localhost:5432/myapp',
    pool: Number(process.env.DB_POOL_SIZE) || 10,
  },
  features: process.env.NODE_ENV === 'production'
    ? ['auth', 'logging', 'monitoring']
    : ['auth', 'logging'],
}

JavaScript Configuration

ES Modules (.mjs)

js
// my-app.config.mjs
export default {
  port: 3000,
  host: 'localhost',
  database: {
    url: 'postgresql://localhost:5432/myapp',
    pool: 10,
  },
}

CommonJS (.cjs)

js
// my-app.config.cjs
module.exports = {
  port: 3000,
  host: 'localhost',
  database: {
    url: 'postgresql://localhost:5432/myapp',
    pool: 10,
  },
}

Regular JavaScript (.js)

js
// my-app.config.js
// Uses project's module type (package.json "type" field)

// If "type": "module" in package.json
export default {
  port: 3000,
  host: 'localhost',
}

// If "type": "commonjs" or no type specified
module.exports = {
  port: 3000,
  host: 'localhost',
}

JSON Configuration

Basic JSON

json
{
  "port": 3000,
  "host": "localhost",
  "database": {
    "url": "postgresql://localhost:5432/myapp",
    "pool": 10
  },
  "features": ["auth", "logging"]
}

JSON with Comments (JSONC)

bunfig supports JSON with comments when using appropriate tooling:

jsonc
{
  // Server configuration
  "port": 3000,
  "host": "localhost",

  /* Database settings */
  "database": {
    "url": "postgresql://localhost:5432/myapp",
    "pool": 10
  },

  "features": [
    "auth", // Authentication module
    "logging" // Logging module
  ]
}

Module Types

ES Modules (.mts)

ts
// my-app.config.mts
import type { Config } from './types.js'

const config: Config = {
  port: 3000,
  host: 'localhost',
}

export default config

CommonJS (.cts)

ts
// my-app.config.cts
import type { Config } from './types'

const config: Config = {
  port: 3000,
  host: 'localhost',
}

export = config

Advanced Patterns

Environment-Specific Configurations

ts
// my-app.config.ts
const baseConfig = {
  host: 'localhost',
  features: ['auth'],
}

const envConfigs = {
  development: {
    ...baseConfig,
    port: 3000,
    debug: true,
  },
  production: {
    ...baseConfig,
    port: 8080,
    debug: false,
    features: [...baseConfig.features, 'monitoring'],
  },
  test: {
    ...baseConfig,
    port: 3001,
    database: {
      url: ':memory:',
    },
  },
}

export default envConfigs[process.env.NODE_ENV as keyof typeof envConfigs] || envConfigs.development

Conditional Exports

ts
// my-app.config.ts
const isDevelopment = process.env.NODE_ENV === 'development'
const isProduction = process.env.NODE_ENV === 'production'

export default {
  port: 3000,
  host: 'localhost',
  ...(isDevelopment && {
    debug: true,
    hotReload: true,
  }),
  ...(isProduction && {
    minify: true,
    compression: true,
  }),
}

Factory Pattern

ts
// my-app.config.ts
interface ConfigOptions {
  env: 'development' | 'production' | 'test'
  debug?: boolean
}

function createConfig(options: ConfigOptions) {
  return {
    port: options.env === 'production' ? 8080 : 3000,
    host: 'localhost',
    debug: options.debug ?? options.env === 'development',
    features: options.env === 'production'
      ? ['auth', 'logging', 'monitoring']
      : ['auth', 'logging'],
  }
}

export default createConfig({
  env: (process.env.NODE_ENV as any) || 'development',
  debug: process.env.DEBUG === 'true',
})

File Naming Conventions

bunfig supports multiple naming conventions for configuration files:

Standard Patterns

my-app.config.ts      # Standard format
.my-app.config.ts     # Hidden/dotfile format
my-app.ts             # Short format
.my-app.ts            # Hidden short format

Directory-Based

config/
├── my-app.ts         # Preferred in config directory
├── my-app.config.ts  # Alternative in config directory
├── .my-app.ts        # Hidden format
└── .my-app.config.ts # Hidden standard format

.config/
├── my-app.ts         # Same patterns as config/
└── my-app.config.ts

Custom Directory

ts
const config = await loadConfig({
  name: 'my-app',
  configDir: './settings', // Custom config directory
  defaultConfig: { /* ... */ },
})
settings/
├── my-app.ts
├── my-app.config.ts
└── other-configs.ts

Format-Specific Features

TypeScript Benefits

  • Type checking at configuration load time
  • IntelliSense support in editors
  • Import/export of shared types and utilities
  • Conditional logic with full TypeScript features

JavaScript Benefits

  • Dynamic configuration with runtime logic
  • Module imports for shared utilities
  • Environment variable integration
  • Compatibility with existing JavaScript tooling

JSON Benefits

  • Simple syntax for basic configurations
  • Easy parsing and validation
  • Tool compatibility with configuration editors
  • Version control friendly format

Best Practices

1. Choose the Right Format

  • TypeScript: For complex configurations with type safety
  • JavaScript: For dynamic configurations with runtime logic
  • JSON: For simple, static configurations

2. Consistent Naming

Use consistent naming patterns across your project:

ts
// Good - consistent pattern
my - app.config.ts
my - api.config.ts
my - cli.config.ts

// Avoid - mixed patterns
my - app.config.ts
api - config.js
cli.json

3. Type Safety

When using TypeScript, define and use interfaces:

ts
// config-types.ts
// my-app.config.ts
import type { AppConfig } from './config-types.ts'

export interface AppConfig {
  port: number
  host: string
  database: DatabaseConfig
}

export interface DatabaseConfig {
  url: string
  pool: number
}

const config: AppConfig = {
  port: 3000,
  host: 'localhost',
  database: {
    url: 'postgresql://localhost:5432/myapp',
    pool: 10,
  },
}

export default config

4. Environment Variables

Integrate environment variables appropriately for each format:

ts
// TypeScript/JavaScript
export default {
  port: Number(process.env.PORT) || 3000,
  debug: process.env.DEBUG === 'true',
}
json
// JSON (use templating tools or build-time replacement)
{
  "port": "${PORT:-3000}",
  "debug": "${DEBUG:-false}"
}

Troubleshooting

Format Not Recognized

  1. Check file extension spelling
  2. Verify the file is in a searched directory
  3. Ensure proper export syntax for the format

Module Loading Errors

  1. Check package.json "type" field for .js files
  2. Verify import/export syntax matches module type
  3. Ensure TypeScript configuration is correct for .ts files

Precedence Issues

  1. Remember the format priority order
  2. Check for multiple files with the same base name
  3. Use specific extensions to avoid conflicts

Released under the MIT License.