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

@apollo-deploy/config

v1.0.1

Published

Shared configuration package for all Apollo applications. This package provides a single source of truth for configuration that is shared across `apollo-app`, `apollo-auth`, and `apollo-marketing`.

Readme

@apollo-deploy/config

Shared configuration package for all Apollo applications. This package provides a single source of truth for configuration that is shared across apollo-app, apollo-auth, and apollo-marketing.

Overview

The config package centralizes shared configuration to ensure consistency across all Apollo applications while maintaining the ability for apps to override specific values when needed.

Key Benefits

  • Single Source of Truth: All shared configuration lives in one place
  • Type Safety: Full TypeScript support with IntelliSense and type checking
  • Consistency: Ensures all applications use the same configuration structure
  • Flexibility: Applications can override specific values while inheriting shared defaults
  • Maintainability: Update configuration once, propagate to all applications
  • Validation: Environment variables are validated at runtime using Zod schemas

Package Structure

packages/config/
├── src/                          # Source files
│   ├── auth/                     # Authentication configuration
│   │   ├── index.ts              # Auth barrel export
│   │   ├── session.ts            # Session management config
│   │   ├── password.ts           # Password policy config
│   │   └── verification.ts       # Email/password verification config
│   │
│   ├── api/                      # API configuration
│   │   ├── index.ts              # API barrel export
│   │   ├── endpoints.ts          # API endpoint URLs
│   │   ├── request.ts            # Request settings (timeout, retry)
│   │   └── cache.ts              # Cache configuration
│   │
│   ├── g11n/                     # Globalization configuration
│   │   ├── index.ts              # G11n barrel export
│   │   ├── locales.ts            # Supported locales
│   │   └── i18n.ts               # i18n configuration
│   │
│   ├── connectors/               # Platform connector definitions
│   │   ├── index.ts              # Connectors barrel export
│   │   ├── types.ts              # Connector type definitions
│   │   └── definitions.ts        # Connector configurations
│   │
│   ├── theme/                    # Theme configuration
│   │   ├── index.ts              # Theme barrel export
│   │   ├── colors.ts             # Color scheme
│   │   ├── typography.ts         # Typography settings
│   │   └── animation.ts          # Animation configuration
│   │
│   ├── env/                      # Environment configuration
│   │   └── index.ts              # Environment exports (placeholder)
│   │
│   └── index.ts                  # Main barrel export (re-exports all domains)
│
├── dist/                         # Build output (generated)
│   ├── **/*.js                   # Compiled JavaScript
│   └── **/*.d.ts                 # TypeScript declarations
│
├── eslint/                       # ESLint configuration
│   └── base.js                   # Base ESLint config
│
├── tailwind/                     # Tailwind configuration
│   └── preset.js                 # Tailwind preset
│
├── typescript/                   # TypeScript configuration
│   ├── base.json                 # Base tsconfig
│   └── nextjs.json               # Next.js-specific tsconfig
│
├── package.json                  # Package manifest
├── tsconfig.json                 # TypeScript configuration
└── README.md                     # This file

Directory Organization

Each domain module follows a consistent structure:

  1. Domain directory (auth/, api/, etc.)

    • Contains all configuration related to that domain
    • Organized by concern (e.g., session.ts, password.ts)
  2. Domain index.ts

    • Re-exports all configuration from the domain
    • Provides a unified domain config object
    • Acts as the public API for the domain
  3. Main index.ts

    • Re-exports all domain modules
    • Provides the unified config object
    • Includes comprehensive JSDoc documentation

Installation

The package is automatically available in the monorepo workspace. Add it to your app's dependencies:

{
  "dependencies": {
    "@apollo-deploy/config": "*"
  }
}

Usage

Importing Configuration

There are three ways to import configuration, each with different use cases:

1. Import from Specific Domain Modules (Recommended for Tree-Shaking)

// Import from specific domain modules
import { authConfig } from '@apollo-deploy/config/auth';
import { apiConfig } from '@apollo-deploy/config/api';
import { SUPPORTED_LOCALES } from '@apollo-deploy/config/g11n';
import { CONNECTORS } from '@apollo-deploy/config/connectors';
import { themeConfig } from '@apollo-deploy/config/theme';

Best for: When you only need specific configuration domains and want optimal tree-shaking.

2. Import from Main Barrel Export

// Import multiple configs from main barrel
import { authConfig, apiConfig, themeConfig } from '@apollo-deploy/config';

Best for: When you need multiple configuration domains and want cleaner imports.

3. Import Unified Config Object

// Import the unified config object
import { config } from '@apollo-deploy/config';

// Access nested configuration
const sessionDuration = config.auth.session.duration;
const apiTimeout = config.api.request.timeout;
const primaryColor = config.theme.colors.primary.light;

Best for: When you need to access configuration from multiple domains in one place, or when passing configuration as a single object.

Domain Modules

Authentication (@apollo-deploy/config/auth)

Provides session management, password policies, and verification settings.

import { authConfig } from '@apollo-deploy/config/auth';

// Access session configuration
const sessionDuration = authConfig.session.duration;
const cookieSettings = authConfig.session.cookie;

// Access password policy
const minLength = authConfig.password.minLength;

API (@apollo-deploy/config/api)

Provides API endpoint definitions, request settings, and cache configuration.

import { apiConfig } from '@apollo-deploy/config/api';

// Access API endpoints
const baseUrl = apiConfig.endpoints.baseUrl;

// Access request configuration
const timeout = apiConfig.request.timeout;
const retrySettings = apiConfig.request.retry;

Globalization (@apollo-deploy/config/g11n)

Provides locale definitions and i18n configuration.

import { g11nConfig, SUPPORTED_LOCALES } from '@apollo-deploy/config/g11n';

// Access supported locales
const locales = SUPPORTED_LOCALES;
const defaultLocale = g11nConfig.defaultLocale;

Connectors (@apollo-deploy/config/connectors)

Provides platform connector definitions (Google Play, App Store, etc.).

import { CONNECTORS } from '@apollo-deploy/config/connectors';

// Access connector definitions
const googlePlayConnector = CONNECTORS.find(c => c.id === 'google-play');

Theme (@apollo-deploy/config/theme)

Provides color schemes, typography, and animation settings.

import { themeConfig } from '@apollo-deploy/config/theme';

// Access theme settings
const defaultMode = themeConfig.mode.defaultMode;
const colors = themeConfig.colors;

Environment (@apollo-deploy/config/env)

Provides environment variable validation and type-safe access.

Note: The environment module is currently a placeholder and will be populated during the environment configuration migration task.

import { env, isDevelopment, getApiUrl } from '@apollo-deploy/config/env';

// Type-safe environment access
const apiUrl = env.NEXT_PUBLIC_API_URL;

// Helper functions
if (isDevelopment()) {
  console.log('Running in development mode');
}

const url = getApiUrl();

Overriding Configuration

Applications can override shared configuration by importing and extending it. This pattern allows apps to customize specific values while inheriting all other shared defaults.

Basic Override Pattern

// In apps/apollo-app/src/config/app.config.ts
import { authConfig as sharedAuthConfig } from '@apollo-deploy/config/auth';

export const authConfig = {
  ...sharedAuthConfig,
  session: {
    ...sharedAuthConfig.session,
    duration: 14 * 24 * 60 * 60 * 1000, // Override: 14 days instead of 7
  },
};

Override Pattern Examples

Example 1: Override Nested Configuration

// Override API timeout for a specific app
import { apiConfig as sharedApiConfig } from '@apollo-deploy/config/api';

export const apiConfig = {
  ...sharedApiConfig,
  request: {
    ...sharedApiConfig.request,
    timeout: 60000, // Override: 60 seconds instead of default 30
    retry: {
      ...sharedApiConfig.request.retry,
      maxRetries: 5, // Override: 5 retries instead of default 3
    },
  },
};

Example 2: Override Multiple Domains

// Override configuration from multiple domains
import { authConfig, apiConfig } from '@apollo-deploy/config';

export const appConfig = {
  auth: {
    ...authConfig,
    session: {
      ...authConfig.session,
      duration: 14 * 24 * 60 * 60 * 1000, // 14 days
    },
  },
  api: {
    ...apiConfig,
    request: {
      ...apiConfig.request,
      timeout: 60000, // 60 seconds
    },
  },
};

Example 3: Override with Environment-Specific Values

// Override based on environment
import { authConfig as sharedAuthConfig } from '@apollo-deploy/config/auth';

const isDevelopment = process.env.NODE_ENV === 'development';

export const authConfig = {
  ...sharedAuthConfig,
  session: {
    ...sharedAuthConfig.session,
    // Longer session in development for convenience
    duration: isDevelopment 
      ? 30 * 24 * 60 * 60 * 1000  // 30 days in dev
      : 7 * 24 * 60 * 60 * 1000,  // 7 days in prod
    cookie: {
      ...sharedAuthConfig.session.cookie,
      // Secure cookies only in production
      secure: !isDevelopment,
    },
  },
};

Example 4: Override Using the Unified Config Object

// Override using the unified config object
import { config } from '@apollo-deploy/config';

export const appConfig = {
  ...config,
  auth: {
    ...config.auth,
    session: {
      ...config.auth.session,
      duration: 14 * 24 * 60 * 60 * 1000,
    },
  },
};

Example 5: Partial Override with Type Safety

// Create a type-safe partial override
import type { Config } from '@apollo-deploy/config';
import { config } from '@apollo-deploy/config';

// TypeScript will enforce correct structure
const overrides: Partial<Config> = {
  auth: {
    ...config.auth,
    session: {
      ...config.auth.session,
      duration: 14 * 24 * 60 * 60 * 1000,
    },
  },
};

export const appConfig = {
  ...config,
  ...overrides,
};

Override Pattern Best Practices

  1. Import the shared config - Always start with the shared configuration as your base
  2. Spread the base - Use object spread (...) to preserve all shared values
  3. Override selectively - Only override the specific values you need to change
  4. Maintain type safety - TypeScript will ensure your overrides are type-compatible
  5. Document overrides - Add comments explaining why the override is necessary
  6. Test overrides - Verify that your overrides work as expected and don't break functionality
  7. Keep overrides minimal - The more you override, the more you diverge from shared standards
  8. Consider environment variables - For values that change between environments, use environment variables instead of overrides

When to Override vs. When to Modify Shared Config

Override in your app when:

  • The configuration is truly app-specific (e.g., longer session for admin app)
  • You're experimenting with a value before making it shared
  • The value differs based on app-specific requirements

Modify shared config when:

  • Multiple apps need the same change
  • The configuration represents a business rule that should be consistent
  • You're fixing a bug or improving a default value

Common Override Pitfalls

Don't: Override without spreading the base

// BAD: This loses all other session properties
export const authConfig = {
  session: {
    duration: 14 * 24 * 60 * 60 * 1000,
  },
};

Do: Always spread the base configuration

// GOOD: This preserves all other session properties
export const authConfig = {
  ...sharedAuthConfig,
  session: {
    ...sharedAuthConfig.session,
    duration: 14 * 24 * 60 * 60 * 1000,
  },
};

Don't: Override with incompatible types

// BAD: TypeScript will catch this error
export const authConfig = {
  ...sharedAuthConfig,
  session: {
    ...sharedAuthConfig.session,
    duration: "14 days", // Error: should be number, not string
  },
};

Do: Maintain type compatibility

// GOOD: Type-safe override
export const authConfig = {
  ...sharedAuthConfig,
  session: {
    ...sharedAuthConfig.session,
    duration: 14 * 24 * 60 * 60 * 1000, // Correct type: number
  },
};

Real-World Usage Examples

Example 1: Using Auth Config in a Login Component

// In apps/apollo-auth/src/components/auth/login-form.tsx
import { authConfig } from '@apollo-deploy/config/auth';
import { useState } from 'react';

export function LoginForm() {
  const [rememberMe, setRememberMe] = useState(false);
  
  const handleSubmit = async (email: string, password: string) => {
    // Use session duration from config
    const sessionDuration = rememberMe 
      ? authConfig.session.rememberMeDuration 
      : authConfig.session.duration;
    
    // Use cookie settings from config
    const cookieOptions = {
      ...authConfig.session.cookie,
      maxAge: sessionDuration,
    };
    
    // Authenticate user...
  };
  
  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields */}
      {authConfig.session.enableRememberMe && (
        <label>
          <input 
            type="checkbox" 
            checked={rememberMe}
            onChange={(e) => setRememberMe(e.target.checked)}
          />
          Remember me for {authConfig.session.rememberMeDuration / (24 * 60 * 60 * 1000)} days
        </label>
      )}
    </form>
  );
}

Example 2: Using API Config in a Data Fetching Hook

// In apps/apollo-app/src/hooks/use-fetch-data.ts
import { apiConfig } from '@apollo-deploy/config/api';
import useSWR from 'swr';

export function useFetchData<T>(endpoint: string) {
  const fetcher = async (url: string) => {
    const controller = new AbortController();
    const timeoutId = setTimeout(
      () => controller.abort(),
      apiConfig.request.timeout
    );
    
    try {
      const response = await fetch(url, {
        signal: controller.signal,
        credentials: apiConfig.request.withCredentials ? 'include' : 'omit',
      });
      
      clearTimeout(timeoutId);
      
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
      
      return response.json();
    } catch (error) {
      clearTimeout(timeoutId);
      throw error;
    }
  };
  
  return useSWR<T>(
    `${apiConfig.endpoints.baseUrl}${endpoint}`,
    fetcher,
    {
      revalidateOnFocus: false,
      dedupingInterval: apiConfig.cache.defaultTTL,
    }
  );
}

Example 3: Using Theme Config in a Theme Provider

// In apps/apollo-app/src/providers/theme-provider.tsx
import { themeConfig } from '@apollo-deploy/config/theme';
import { createContext, useContext, useEffect, useState } from 'react';

type Theme = 'light' | 'dark' | 'system';

const ThemeContext = createContext<{
  theme: Theme;
  setTheme: (theme: Theme) => void;
}>({
  theme: themeConfig.mode.defaultMode,
  setTheme: () => {},
});

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme, setTheme] = useState<Theme>(() => {
    if (!themeConfig.mode.enablePersistence) {
      return themeConfig.mode.defaultMode;
    }
    
    const stored = localStorage.getItem(themeConfig.mode.storageKey);
    return (stored as Theme) || themeConfig.mode.defaultMode;
  });
  
  useEffect(() => {
    if (themeConfig.mode.enablePersistence) {
      localStorage.setItem(themeConfig.mode.storageKey, theme);
    }
    
    // Apply theme to document
    const root = document.documentElement;
    root.classList.remove('light', 'dark');
    
    if (theme === 'system') {
      const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
        ? 'dark'
        : 'light';
      root.classList.add(systemTheme);
    } else {
      root.classList.add(theme);
    }
  }, [theme]);
  
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

export const useTheme = () => useContext(ThemeContext);

Example 4: Using Connector Config in a Settings Page

// In apps/apollo-app/src/features/settings/components/connectors-list.tsx
import { CONNECTORS } from '@apollo-deploy/config/connectors';

export function ConnectorsList() {
  return (
    <div className="grid gap-4">
      {CONNECTORS.map((connector) => (
        <div key={connector.id} className="border rounded-lg p-4">
          <div className="flex items-center gap-3">
            {connector.icon}
            <div>
              <h3 className="font-semibold">{connector.name}</h3>
              <p className="text-sm text-muted-foreground">
                {connector.description}
              </p>
            </div>
          </div>
          
          {connector.supportedRegions && (
            <div className="mt-2 text-sm">
              <span className="font-medium">Regions:</span>{' '}
              {connector.supportedRegions.join(', ')}
            </div>
          )}
          
          <button className="mt-3">
            {connector.connectLabel || 'Connect'}
          </button>
        </div>
      ))}
    </div>
  );
}

Example 5: Using G11n Config in an i18n Setup

// In apps/apollo-app/src/lib/i18n.ts
import { SUPPORTED_LOCALES, DEFAULT_LOCALE, createI18nConfig } from '@apollo-deploy/config/g11n';
import i18next from 'i18next';
import { initReactI18next } from 'react-i18next';

// Create app-specific i18n config with custom namespaces
const i18nConfig = createI18nConfig([
  'common',
  'auth',
  'settings',
  'webhooks',
  'workflows',
]);

i18next
  .use(initReactI18next)
  .init({
    ...i18nConfig,
    resources: {
      // Load translations for each supported locale
      ...SUPPORTED_LOCALES.reduce((acc, locale) => {
        acc[locale.code] = {
          common: require(`@/locales/${locale.code}/common.json`),
          auth: require(`@/locales/${locale.code}/auth.json`),
          settings: require(`@/locales/${locale.code}/settings.json`),
          webhooks: require(`@/locales/${locale.code}/webhooks.json`),
          workflows: require(`@/locales/${locale.code}/workflows.json`),
        };
        return acc;
      }, {} as Record<string, any>),
    },
  });

export default i18next;

Example 6: Using Unified Config Object

// In apps/apollo-app/src/lib/app-config.ts
import { config } from '@apollo-deploy/config';

// Access multiple config domains from one import
export function getAppMetadata() {
  return {
    // Auth settings
    sessionDuration: config.auth.session.duration,
    passwordMinLength: config.auth.password.minLength,
    
    // API settings
    apiBaseUrl: config.api.endpoints.baseUrl,
    apiTimeout: config.api.request.timeout,
    
    // Theme settings
    defaultTheme: config.theme.mode.defaultMode,
    primaryColor: config.theme.colors.primary.light,
    
    // G11n settings
    defaultLocale: config.g11n.defaultLocale,
    supportedLocales: config.g11n.supportedLocales.map(l => l.code),
    
    // Connectors
    availableConnectors: config.connectors.length,
  };
}

Development

Building

npm run build

Type Checking

npm run typecheck

Linting

npm run lint

Adding New Configuration

When adding new configuration to this package, follow these steps to ensure consistency and maintainability.

Step-by-Step Guide

1. Choose the Right Domain

Place configuration in the appropriate domain module:

  • auth/ - Authentication, authorization, sessions, passwords
  • api/ - API endpoints, request settings, cache configuration
  • g11n/ - Locales, translations, internationalization
  • connectors/ - Third-party platform integrations
  • theme/ - Colors, typography, animations, UI styling
  • env/ - Environment variables, validation schemas

If your configuration doesn't fit any existing domain, consider creating a new domain module.

2. Define TypeScript Interfaces

Create clear, well-documented interfaces with JSDoc comments:

// In packages/config/src/auth/mfa.ts

/**
 * Multi-factor authentication configuration
 * 
 * Controls MFA behavior including supported methods,
 * backup codes, and enforcement policies.
 */
export interface MfaConfig {
  /**
   * Whether MFA is enabled for the application
   * @default true
   */
  enabled: boolean;
  
  /**
   * Supported MFA methods
   * @default ['totp', 'sms']
   */
  supportedMethods: ('totp' | 'sms' | 'email')[];
  
  /**
   * Number of backup codes to generate
   * @default 10
   */
  backupCodeCount: number;
  
  /**
   * Whether to enforce MFA for all users
   * @default false
   */
  enforceForAllUsers: boolean;
  
  /**
   * Grace period before MFA enforcement (in days)
   * @default 7
   */
  enforcementGracePeriod: number;
}

/**
 * Multi-factor authentication configuration
 * 
 * @example
 * ```typescript
 * import { MFA_CONFIG } from '@apollo-deploy/config/auth';
 * 
 * if (MFA_CONFIG.enabled) {
 *   // Show MFA setup flow
 * }
 * ```
 */
export const MFA_CONFIG: MfaConfig = {
  enabled: true,
  supportedMethods: ['totp', 'sms'],
  backupCodeCount: 10,
  enforceForAllUsers: false,
  enforcementGracePeriod: 7,
} as const;

3. Export from Domain Index

Add exports to the domain's index.ts:

// In packages/config/src/auth/index.ts

export * from './session';
export * from './password';
export * from './verification';
export * from './mfa'; // Add new export

// Update the unified authConfig if needed
import { SESSION_CONFIG } from './session';
import { PASSWORD_POLICY } from './password';
import { EMAIL_VERIFICATION_CONFIG, PASSWORD_RESET_CONFIG } from './verification';
import { MFA_CONFIG } from './mfa'; // Import new config

export const authConfig = {
  session: SESSION_CONFIG,
  password: PASSWORD_POLICY,
  emailVerification: EMAIL_VERIFICATION_CONFIG,
  passwordReset: PASSWORD_RESET_CONFIG,
  mfa: MFA_CONFIG, // Add to unified config
} as const;

4. Update Main Barrel (if needed)

The main index.ts already re-exports all domains, but you may need to update the unified config object:

// In packages/config/src/index.ts

// The domain exports are already handled by:
export * from './auth';

// Update the unified config object if you added a new domain
export const config = {
  auth: authConfig,
  api: apiConfig,
  theme: themeConfig,
  connectors: CONNECTORS,
  g11n: { /* ... */ },
  // Add new domain here if you created one
} as const;

5. Document in README

Add usage examples to this README:

#### Multi-Factor Authentication (`@apollo-deploy/config/auth`)

Provides MFA configuration including supported methods and enforcement policies.

\`\`\`typescript
import { MFA_CONFIG } from '@apollo-deploy/config/auth';

// Check if MFA is enabled
if (MFA_CONFIG.enabled) {
  // Show MFA setup
}

// Get supported methods
const methods = MFA_CONFIG.supportedMethods;
\`\`\`

6. Add JSDoc Comments

Document all exported values and types with JSDoc:

/**
 * Brief description of what this config does
 * 
 * More detailed explanation if needed. Include:
 * - What problem it solves
 * - When to use it
 * - Any important caveats
 * 
 * @example
 * ```typescript
 * import { CONFIG_NAME } from '@apollo-deploy/config/domain';
 * 
 * // Show usage example
 * const value = CONFIG_NAME.property;
 * ```
 * 
 * @see {@link RelatedType} for related configuration
 */
export const CONFIG_NAME = { /* ... */ } as const;

Best Practices for New Configuration

  1. Use as const for immutability

    export const CONFIG = {
      value: 'example',
    } as const; // Makes the object deeply readonly
  2. Provide sensible defaults

    export const CONFIG = {
      enabled: true, // Safe default
      timeout: 30000, // Reasonable timeout
    } as const;
  3. Use environment variables for runtime values

    export const CONFIG = {
      apiUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000',
      debug: process.env.NODE_ENV === 'development',
    } as const;
  4. Group related configuration

    // Good: Related settings grouped together
    export const SESSION_CONFIG = {
      duration: 7 * 24 * 60 * 60 * 1000,
      refreshThreshold: 24 * 60 * 60 * 1000,
      enableRefresh: true,
    } as const;
       
    // Avoid: Scattered individual exports
    export const SESSION_DURATION = 7 * 24 * 60 * 60 * 1000;
    export const REFRESH_THRESHOLD = 24 * 60 * 60 * 1000;
    export const ENABLE_REFRESH = true;
  5. Use TypeScript enums or union types for fixed values

    export type AuthMethod = 'password' | 'oauth' | 'magic-link';
       
    export const AUTH_CONFIG = {
      supportedMethods: ['password', 'oauth'] as AuthMethod[],
    } as const;
  6. Avoid business logic in config

    // ❌ Bad: Business logic in config
    export const CONFIG = {
      calculateDiscount: (price: number) => price * 0.9,
    };
       
    // ✅ Good: Pure data
    export const CONFIG = {
      discountPercentage: 0.9,
    } as const;
  7. Consider override-ability

    // Make it easy for apps to override
    export const CONFIG = {
      // Flat structure is easier to override
      timeout: 30000,
      retries: 3,
    } as const;
       
    // Instead of deeply nested
    export const CONFIG = {
      request: {
        settings: {
          timeout: { value: 30000 },
        },
      },
    } as const;

Testing New Configuration

After adding new configuration:

  1. Build the package

    cd packages/config
    npm run build
  2. Check type generation

    # Verify .d.ts files were created
    ls dist/**/*.d.ts
  3. Test imports in an app

// In apps/apollo-app/src/test-config.ts import { NEW_CONFIG } from '@apollo-deploy/config/domain';

console.log(NEW_CONFIG);


4. **Verify TypeScript IntelliSense**
- Open an app file
- Type `import { ` and verify your new config appears in autocomplete
- Hover over the import to see JSDoc documentation

5. **Test overrides**
```typescript
// Verify apps can override your config
import { NEW_CONFIG } from '@apollo-deploy/config/domain';

const overridden = {
  ...NEW_CONFIG,
  someProperty: 'new value',
};

Troubleshooting

Module Resolution Errors

Problem: You see errors like Cannot find module '@apollo-deploy/config' or Module not found: Can't resolve '@apollo-deploy/config'

Solutions:

  1. Check package.json dependencies

    {
      "dependencies": {
        "@apollo-deploy/config": "*"
      }
    }

    Ensure @apollo-deploy/config is listed in your app's package.json.

  2. Install dependencies

    # From workspace root
    npm install
       
    # Or using Turborepo
    turbo install
  3. Restart TypeScript server

    • In VS Code: Cmd/Ctrl + Shift + P → "TypeScript: Restart TS Server"
    • Or restart your IDE
  4. Clear build cache

    # Clear Turborepo cache
    turbo clean
       
    # Clear Next.js cache
    rm -rf apps/*/.next
       
    # Reinstall
    npm install

Type Errors

Problem: You see type errors when importing from @apollo-deploy/config, such as Property 'session' does not exist on type 'typeof import(...)'

Solutions:

  1. Build the config package

    # From workspace root
    npm run build
       
    # Or build just the config package
    cd packages/config && npm run build
  2. Check tsconfig.json paths

    {
      "compilerOptions": {
        "paths": {
          "@apollo-deploy/config": ["../../packages/config/src"],
          "@apollo-deploy/config/*": ["../../packages/config/src/*"]
        }
      }
    }
  3. Verify type declarations exist

    # Check that .d.ts files were generated
    ls packages/config/dist/**/*.d.ts
  4. Restart TypeScript server (see above)

Import Path Errors

Problem: Imports work in some files but not others, or you get inconsistent behavior

Solutions:

  1. Use consistent import paths

    // ✅ GOOD: Use package name
    import { authConfig } from '@apollo-deploy/config';
       
    // ❌ BAD: Don't use relative paths to packages
    import { authConfig } from '../../packages/config/src/auth';
  2. Check for typos in import paths

    // ✅ GOOD
    import { authConfig } from '@apollo-deploy/config/auth';
       
    // ❌ BAD: Typo in path
    import { authConfig } from '@apollo-deploy/config/auths';

Circular Dependencies

Problem: You see warnings like Circular dependency detected or build failures related to circular imports

Solutions:

  1. Check for app imports in config package

    # Search for imports from apps in config package
    grep -r "from.*apps/" packages/config/src/

    The config package should NEVER import from applications.

  2. Move app-specific logic out of config If you find app-specific code in the config package, move it to the appropriate app's src/config/ directory.

  3. Use proper dependency direction

    • ✅ Apps can import from @apollo-deploy/config
    • @apollo-deploy/config cannot import from apps

Override Not Working

Problem: Your configuration override doesn't seem to take effect

Solutions:

  1. Verify you're using the overridden config

    // Make sure you're importing YOUR config, not the shared one
       
    // ❌ BAD: Still using shared config
    import { authConfig } from '@apollo-deploy/config';
       
    // ✅ GOOD: Using your overridden config
    import { authConfig } from '@/config/app.config';
  2. Check object spread order

    // ❌ BAD: Override comes first, gets overwritten by spread
    export const authConfig = {
      session: { duration: 14 * 24 * 60 * 60 * 1000 },
      ...sharedAuthConfig,
    };
       
    // ✅ GOOD: Spread first, then override
    export const authConfig = {
      ...sharedAuthConfig,
      session: {
        ...sharedAuthConfig.session,
        duration: 14 * 24 * 60 * 60 * 1000,
      },
    };
  3. Verify nested spreading

    // ❌ BAD: Missing nested spread
    export const authConfig = {
      ...sharedAuthConfig,
      session: {
        duration: 14 * 24 * 60 * 60 * 1000, // Lost other session properties!
      },
    };
       
    // ✅ GOOD: Spread nested objects too
    export const authConfig = {
      ...sharedAuthConfig,
      session: {
        ...sharedAuthConfig.session, // Preserve other properties
        duration: 14 * 24 * 60 * 60 * 1000,
      },
    };

Build Failures

Problem: Build fails with errors related to @apollo-deploy/config

Solutions:

  1. Check build order Ensure turbo.json builds the config package before apps:

    {
      "pipeline": {
        "build": {
          "dependsOn": ["^build"]
        }
      }
    }
  2. Build config package first

    # Build config package explicitly
    turbo build --filter=@apollo-deploy/config
       
    # Then build your app
    turbo build --filter=apollo-app
  3. Check for syntax errors in config files

    # Type check the config package
    cd packages/config
    npm run typecheck

Hot Reload Not Working

Problem: Changes to config package don't trigger hot reload in development

Solutions:

  1. Restart development server

    # Stop dev server (Ctrl+C)
    # Then restart
    npm run dev
  2. Check Turborepo watch configuration Ensure turbo.json has proper watch setup:

    {
      "pipeline": {
        "dev": {
          "dependsOn": ["^build"],
          "cache": false
        }
      }
    }
  3. Use Turborepo dev mode

    # Use Turborepo to run dev servers
    turbo dev

Environment Variable Issues

Problem: Environment variables aren't being validated or accessed correctly

Solutions:

  1. Check .env files exist

    # Each app should have .env or .env.local
    ls apps/*/.env*
  2. Verify environment variable names

    // ✅ GOOD: Correct Next.js public variable
    NEXT_PUBLIC_API_URL=https://api.example.com
       
    // ❌ BAD: Missing NEXT_PUBLIC_ prefix
    API_URL=https://api.example.com
  3. Restart development server after .env changes Next.js only reads .env files on startup.

Getting Help

If you're still experiencing issues:

  1. Check the migration status

    • Some modules (like env/) may still be placeholders
    • Refer to the migration tasks document
  2. Review the design document

    • See .kiro/specs/shared-config-migration/design.md
    • Check if your use case is covered
  3. Ask the team

    • Share the specific error message
    • Include your import statements and usage
    • Mention which app you're working in
  4. Check for updates

    # Pull latest changes
    git pull
       
    # Reinstall dependencies
    npm install
       
    # Rebuild everything
    turbo build

Migration Guide

If you're migrating from app-specific configuration to this shared package, follow these steps:

Step 1: Identify Shared Configuration

Review your app's configuration and identify what should be shared:

// In apps/apollo-app/src/config/app.config.ts

// ✅ Shared: Used by multiple apps
export const SESSION_DURATION = 7 * 24 * 60 * 60 * 1000;
export const PASSWORD_MIN_LENGTH = 8;
export const API_TIMEOUT = 30000;

// ❌ App-specific: Unique to this app
export const APP_NAME = 'Apollo Dashboard';
export const APP_PORT = 3001;
export const DASHBOARD_ROUTES = ['/overview', '/analytics'];

Step 2: Move Shared Config to Package

Move shared configuration to the appropriate domain in @apollo-deploy/config:

// Move to packages/config/src/auth/session.ts
export const SESSION_CONFIG = {
  duration: 7 * 24 * 60 * 60 * 1000,
  // ... other session config
} as const;

// Move to packages/config/src/auth/password.ts
export const PASSWORD_POLICY = {
  minLength: 8,
  // ... other password config
} as const;

// Move to packages/config/src/api/request.ts
export const API_REQUEST_CONFIG = {
  timeout: 30000,
  // ... other API config
} as const;

Step 3: Update Imports in Your App

Replace local imports with @apollo-deploy/config imports:

// Before
import { SESSION_DURATION, PASSWORD_MIN_LENGTH } from '@/config/app.config';

// After
import { SESSION_CONFIG, PASSWORD_POLICY } from '@apollo-deploy/config';

const sessionDuration = SESSION_CONFIG.duration;
const passwordMinLength = PASSWORD_POLICY.minLength;

Step 4: Keep App-Specific Config Local

Keep app-specific configuration in your app's config directory:

// In apps/apollo-app/src/config/app.config.ts

// Import shared config
import { authConfig, apiConfig } from '@apollo-deploy/config';

// App-specific metadata
export const APP_CONFIG = {
  name: 'Apollo Dashboard',
  port: 3001,
  routes: {
    dashboard: '/overview',
    analytics: '/analytics',
  },
} as const;

// Override shared config if needed
export const appAuthConfig = {
  ...authConfig,
  session: {
    ...authConfig.session,
    duration: 14 * 24 * 60 * 60 * 1000, // Override: 14 days
  },
};

Step 5: Remove Duplicate Configuration

After migration, remove duplicate configuration files:

# Remove old config files (if everything is migrated)
rm -rf apps/apollo-app/src/config/auth.config.ts
rm -rf apps/apollo-app/src/config/api.config.ts

# Keep app-specific config
# apps/apollo-app/src/config/app.config.ts (app-specific only)

Step 6: Update Tests

Update tests to import from @apollo-deploy/config:

// Before
import { SESSION_DURATION } from '@/config/app.config';

// After
import { SESSION_CONFIG } from '@apollo-deploy/config';

test('session duration', () => {
  expect(SESSION_CONFIG.duration).toBe(7 * 24 * 60 * 60 * 1000);
});

Step 7: Verify Migration

  1. Build all apps

    turbo build
  2. Run all tests

    turbo test
  3. Check for duplicate config

    # Search for duplicate configuration values
    grep -r "SESSION_DURATION" apps/
    grep -r "PASSWORD_MIN_LENGTH" apps/
  4. Verify imports

    # Ensure all apps import from @apollo-deploy/config
    grep -r "from '@apollo-deploy/config'" apps/

Migration Checklist

  • [ ] Identified shared vs. app-specific configuration
  • [ ] Moved shared config to @apollo-deploy/config
  • [ ] Updated imports in all apps
  • [ ] Kept app-specific config in app directories
  • [ ] Removed duplicate configuration files
  • [ ] Updated tests to use new imports
  • [ ] Verified all apps build successfully
  • [ ] Verified all tests pass
  • [ ] Checked for remaining duplicate config
  • [ ] Documented any app-specific overrides

Architecture

This package follows the monorepo principle: "Apps are Consumers". Applications are thin shells that compose configuration from shared packages rather than maintaining duplicate config definitions.

Dependency Rules

  • ✅ Applications can import from @apollo-deploy/config
  • ✅ Config package can import from other packages (e.g., zod)
  • ❌ Config package CANNOT import from applications
  • ❌ Config package should not contain business logic

Design Principles

  1. Single Source of Truth: Shared configuration lives in one place
  2. Type Safety: Full TypeScript support with strict typing
  3. Immutability: Configuration objects use as const for immutability
  4. Composability: Apps can compose and override configuration
  5. Documentation: All exports have JSDoc comments
  6. Discoverability: Clear structure and barrel exports make config easy to find

Frequently Asked Questions

General Questions

Q: Why do we need a shared config package?

A: The shared config package eliminates duplication, ensures consistency across apps, and provides a single source of truth for configuration. It makes it easier to update configuration and reduces the risk of inconsistencies.

Q: Can I still have app-specific configuration?

A: Yes! Keep app-specific configuration in your app's src/config/ directory. Only shared configuration should live in @apollo-deploy/config.

Q: What's the difference between shared and app-specific config?

A: Shared config is used by multiple apps (e.g., session duration, password policy). App-specific config is unique to one app (e.g., app name, app-specific routes).

Import Questions

Q: Should I import from @apollo-deploy/config or @apollo-deploy/config/auth?

A: Both work! Import from specific domains (@apollo-deploy/config/auth) for better tree-shaking, or from the main barrel (@apollo-deploy/config) for convenience.

Q: Can I import the unified config object?

A: Yes! import { config } from '@apollo-deploy/config' gives you access to all configuration in one object.

Q: Why can't I import from @apollo-deploy/config?

A: Make sure the package is listed in your package.json dependencies, run npm install, and restart your TypeScript server.

Override Questions

Q: How do I override shared configuration?

A: Import the shared config, spread it, and override specific values:

import { authConfig } from '@apollo-deploy/config';

export const myAuthConfig = {
  ...authConfig,
  session: {
    ...authConfig.session,
    duration: 14 * 24 * 60 * 60 * 1000,
  },
};

Q: Will my overrides break when shared config changes?

A: No! As long as you use the spread operator correctly, your overrides will be preserved and you'll inherit non-overridden changes.

Q: Can I override nested configuration?

A: Yes, but remember to spread nested objects too:

export const config = {
  ...sharedConfig,
  nested: {
    ...sharedConfig.nested, // Don't forget this!
    property: 'override',
  },
};

Q: Should I override in the config package or in my app?

A: Always override in your app. The config package should only contain shared defaults.

Development Questions

Q: Do I need to rebuild the config package after changes?

A: For production builds, yes. In development mode with turbo dev, changes should hot-reload automatically.

Q: How do I add new configuration?

A: See the "Adding New Configuration" section above for a step-by-step guide.

Q: Can the config package import from other packages?

A: Yes, it can import from other shared packages (like zod), but it should NEVER import from applications.

Q: Why am I getting circular dependency warnings?

A: The config package might be importing from an application. Config should only be imported by apps, never the other way around.

Type Safety Questions

Q: Why use as const?

A: as const makes the configuration object deeply readonly and preserves literal types, giving you better type safety and IntelliSense.

Q: How do I get TypeScript IntelliSense for config?

A: Make sure the config package is built (npm run build) and your TypeScript server is running. Hover over imports to see documentation.

Q: Can I use the config in JavaScript files?

A: Yes, but you'll lose type safety. We recommend using TypeScript for better developer experience.

Migration Questions

Q: How do I migrate from app-specific config to shared config?

A: See the "Migration Guide" section above for detailed steps.

Q: What if my app needs different values than other apps?

A: Use the override pattern to customize values for your app while keeping shared defaults.

Q: Do I need to migrate all config at once?

A: No! You can migrate incrementally. Start with the most duplicated configuration and work your way through.

Q: What happens to my old config files after migration?

A: You can delete them if all configuration has been migrated to @apollo-deploy/config or converted to app-specific overrides.

Environment Variables

Q: Where should environment variables be validated?

A: Environment variable validation will be handled by the env/ module (currently a placeholder, to be implemented).

Q: Can I use environment variables in config?

A: Yes! Use process.env.VARIABLE_NAME in your configuration:

export const CONFIG = {
  apiUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000',
} as const;

Q: Should environment variables be in the config package or apps?

A: Shared environment variable schemas should be in @apollo-deploy/config/env. App-specific environment variables stay in the app.

Related Packages

  • @apollo-deploy/core - Shared business logic and types
  • @apollo-deploy/components - Shared UI components
  • packages/config/eslint - ESLint configuration
  • packages/config/typescript - TypeScript configuration

Contributing

When contributing to this package:

  1. Follow the existing structure and patterns
  2. Add comprehensive JSDoc comments
  3. Include usage examples in documentation
  4. Test your changes in at least one application
  5. Update this README with any new configuration
  6. Ensure all builds and tests pass

License

This package is part of the Apollo monorepo and follows the same license as the parent project.