Centralized Config: The siteConfig Pattern
One of the design patterns baked into this template is the centralized site configuration. Instead of scattering configuration across multiple files and environment variables, all site settings live in a single typed object.
The Problem
In a typical multi-app setup, configuration gets messy:
- Analytics IDs in
Astro.locals.runtime.envhere,import.meta.envthere - Site name hardcoded in multiple layouts
- Contact info duplicated across forms and footers
- SEO defaults inconsistent between pages
The Solution: @template/site-config
The packages/site-config/ workspace package exports a single typed siteConfig object:
export const siteConfig = {
name: 'My Company',
description: 'We build amazing things',
analytics: {
ga4Id: 'G-XXXXXXXXXX',
gtmId: 'GTM-XXXXXXX',
cloudflareToken: '...',
},
seo: {
defaultTitle: 'My Company',
defaultDescription: 'We build amazing things',
defaultOgImage: '/og-default.png',
},
social: {
twitter: '@mycompany',
linkedin: 'company/mycompany',
},
contact: {
email: 'hello@mycompany.com',
phone: '+1 (555) 000-0000',
address: '123 Main St, City, ST',
},
};
How It Works
Every app imports siteConfig as a workspace dependency:
---
import { siteConfig } from '@template/site-config';
---
<title>{siteConfig.name}</title>
The pattern eliminates:
- Duplicated configuration across apps
- Inconsistent default values
- Hardcoded strings scattered in layouts
import.meta.envcalls for public config
Runtime vs Build Time
Public configuration (site name, analytics IDs) uses siteConfig at build time. Client-safe values are compiled into the static output. Private configuration (API keys, tokens) uses Astro.locals.runtime.env at runtime — never exposed to the client.
Adding New Config Fields
To add a new setting:
- Add the field to
packages/site-config/src/types.ts - Add the value to
packages/site-config/src/index.ts - Import and use
siteConfigin any app
All three apps get the update automatically — no copy-paste, no drift.
Environment Variable Bridging
For values that come from environment variables (like analytics IDs that differ between preview and production), siteConfig can read from import.meta.env:
analytics: {
ga4Id: import.meta.env.PUBLIC_GA4_ID || '',
}
This keeps the API surface consistent while allowing per-environment overrides.
The siteConfig pattern is one of the template's core architectural decisions. Use it for all shared configuration — your future self (and your team) will thank you.