Site Configuration
Single-file branding: names, contact, navigation, categories, locales, currencies, and theme.
Almost everything that makes the storefront yours lives in a single file:
src/config/site.ts. Components read from this config instead of hardcoding copy,
so rebranding the boilerplate is mostly an exercise in editing it.
This page reflects the values shipped in the boilerplate (the fictional "Kestrel Supply"). Every field name below matches the source exactly — change the values, keep the keys.
What the file exports
src/config/site.ts exports three runtime values plus several TypeScript
interfaces that describe their shape.
| Export | Kind | Purpose |
|---|---|---|
siteConfig | const object | Store identity, contact, navigation, currencies, locales, and theme presets. |
productCategories | ProductCategory[] | The catalog's top-level categories. |
productConfig | const object | The boilerplate's own identity (name, url, tagline), kept separate so renaming your store does not rename the project you forked. Read by the /platform marketing page's nav and footer and by the /docs shell; delete those surfaces if you do not want them. |
CurrencyConfig | interface | Shape of the base store currency (code, locale). |
CurrencyOption | interface | A switchable currency (code, locale, rate, label). |
LocaleOption | interface | A switchable UI locale (code, label). |
ThemePreset | interface | A brand color scheme as HSL triplets. |
ProductCategory | interface | Shape of one entry in productCategories. |
siteConfig is declared as const, so its values are readonly and their literal
types flow through the rest of the app — TypeScript will flag a typo in a category
slug or a currency code at build time.
siteConfig
Identity
export const siteConfig = {
name: "Kestrel Supply",
tagline: "Technology worth keeping",
description:
"Audio, wearables, and smart home gear, tested by our team before it reaches the shelf.",
url: "https://ecommerce-boilerplate.com",
// ...
} as const;| Field | Type | Shipped value | Notes |
|---|---|---|---|
name | string | "Kestrel Supply" | Store name shown in the header, footer, page titles, and emails. |
tagline | string | "Technology worth keeping" | Short marketing line. |
description | string | "Audio, wearables, and smart home gear, tested by our team…" | Long description, used for SEO metadata and the OpenGraph/Twitter cards. |
url | string | "https://ecommerce-boilerplate.com" | Canonical site URL. Point this at your production domain. |
Contact and social links
contact: {
email: "hello@example.com",
phone: "+1 (555) 000-0000",
address: "123 Commerce St, Suite 100, Springfield, USA",
},
links: {
linkedin: "https://www.linkedin.com/company/your-company",
instagram: "https://www.instagram.com/your-company",
github: "https://github.com/nebulanollie/ecommerce-boilerplate",
},| Field | Shipped value |
|---|---|
contact.email | "hello@example.com" |
contact.phone | "+1 (555) 000-0000" |
contact.address | "123 Commerce St, Suite 100, Springfield, USA" |
links.linkedin | "https://www.linkedin.com/company/your-company" |
links.instagram | "https://www.instagram.com/your-company" |
links.github | "https://github.com/nebulanollie/ecommerce-boilerplate" (the boilerplate's own repo, used by the marketing landing and boilerplate bar) |
Navigation
Two navigation arrays drive the header and footer. Each item is a { label, href }
pair — internal routes are plain paths and hash links (/#contact) jump to a section.
mainNav: [
{ label: "Products", href: "/products" },
{ label: "About", href: "/about" },
{ label: "Contact", href: "/#contact" },
],
legalNav: [
{ label: "Privacy Policy", href: "/privacy-policy" },
{ label: "Terms of Service", href: "/terms-of-service" },
{ label: "Cookie Policy", href: "/cookie-policy" },
],| Array | Rendered in | Items (label → href) |
|---|---|---|
mainNav | Primary header/footer navigation | Products → /products, About → /about, Contact → /#contact |
legalNav | Footer legal links | Privacy Policy → /privacy-policy, Terms of Service → /terms-of-service, Cookie Policy → /cookie-policy |
Any internal href must point at a route that actually exists in the app —
nothing validates these at build time.
Currencies
The store has one base currency (currency) and a list of currencies the shopper
can switch into (currencies). Prices are stored in the base currency and converted
for display by formatMoney in src/lib/money.ts.
currency: { code: "USD", locale: "en-US" } satisfies CurrencyConfig,
currencies: [
{ code: "USD", locale: "en-US", rate: 1, label: "USD ($)" },
{ code: "EUR", locale: "de-DE", rate: 0.92, label: "EUR (€)" },
{ code: "GBP", locale: "en-GB", rate: 0.79, label: "GBP (£)" },
{ code: "JPY", locale: "ja-JP", rate: 155, label: "JPY (¥)" },
] satisfies CurrencyOption[],currency(CurrencyConfig) is the single source of truth for how prices render across the storefront, admin, and emails:codeis an ISO 4217 code andlocaleis a BCP 47 locale that drives number grouping and the currency symbol.currencies(CurrencyOption[]) lists the switchable options. Each addsrate— the multiplier from the base currency — andlabel, the short text shown in the switcher.
The first entry in currencies must be the base currency with rate: 1 and must
match siteConfig.currency. The shipped rates (0.92, 0.79, 155) are static demo
values — wire a live FX feed before relying on them in production.
See Currency & pricing for how conversion and formatting work end to end.
Locales
defaultLocale: "en",
locales: [
{ code: "en", label: "English" },
{ code: "es", label: "Español" },
] satisfies LocaleOption[],| Field | Type | Shipped value |
|---|---|---|
defaultLocale | string | "en" |
locales | LocaleOption[] | en → English, es → Español |
Each LocaleOption has a code (a BCP 47 code that must also be registered in the
src/lib/i18n dictionaries) and a native label for the switcher. The first entry is
the default. Adding a language is a data change — drop in src/lib/i18n/<locale>.ts,
register it in dictionaries, and add an entry here.
See Internationalization for the full "how to add a locale" walkthrough.
Theme presets
Brand colors live in the --brand* CSS variables in src/app/globals.css; the
theme block mirrors and documents them so you can swap schemes from one place.
theme: {
active: "default",
presets: {
default: {
brand: "226 57% 21%",
brandForeground: "210 40% 98%",
brandAccent: "24.6 95% 53.1%",
brandAccentForeground: "0 0% 100%",
},
emerald: {
brand: "160 84% 20%",
brandForeground: "150 40% 98%",
brandAccent: "160 84% 39%",
brandAccentForeground: "0 0% 100%",
},
violet: {
brand: "263 60% 26%",
brandForeground: "270 40% 98%",
brandAccent: "262 83% 58%",
brandAccentForeground: "0 0% 100%",
},
} satisfies Record<string, ThemePreset>,
},theme.active is informational only — the runtime source of truth is
globals.css. Each preset is a ThemePreset whose four fields are space-separated
HSL triplets ("H S% L%"), so a value drops straight into hsl(var(--brand)) with no
conversion.
ThemePreset field | Maps to CSS variable | Role |
|---|---|---|
brand | --brand | Deep brand color — headings, dark surfaces, primary brand buttons. |
brandForeground | --brand-foreground | Readable text/icon color on top of brand. |
brandAccent | --brand-accent | Vivid accent — primary CTA buttons and highlights. |
brandAccentForeground | --brand-accent-foreground | Readable text/icon color on top of brandAccent. |
| Preset | Look |
|---|---|
default | Deep navy brand + vivid orange accent (ships out of the box). |
emerald | Green-forward alternative. |
violet | Purple-forward alternative. |
To recolor the store, edit the --brand* values in src/app/globals.css — either
directly or by pasting a preset's triplets onto them. globals.css also defines
brand tokens inside the storefront and admin scopes, which is what decides how far
a preset actually reaches; Branding & theming
has the full picture.
productCategories
productCategories is an array of ProductCategory objects describing the catalog's
top-level categories. They drive the header navigation, the hero, and the category
cards, and their slug powers category filtering via /products?category=<slug>.
export const productCategories: ProductCategory[] = [
{
name: "Audio",
slug: "audio",
icon: "/categories/audio.svg",
image: "/categories/audio.svg",
description:
"Headphones, speakers, and studio gear engineered for rich, accurate sound.",
secondaryDescription:
"From everyday earbuds to reference monitors, our audio lineup covers listening, recording, and everything in between.",
badges: ["Headphones", "Speakers", "Microphones"],
},
// ...five more
];ProductCategory fields
| Field | Type | Purpose |
|---|---|---|
name | string | Display name shown in navigation and cards. |
slug | string | URL-safe identifier used in query strings: /products?category=<slug>. |
icon | string | Small icon shown in the header navigation and hero. |
image | string | Larger image shown on category cards. |
description | string | Short marketing copy for the category card. |
secondaryDescription | string (optional) | Longer supporting copy for the category card. |
badges | string[] | Example product types shown as badges on the category card. |
Shipped categories
name | slug | badges |
|---|---|---|
| Audio | audio | Headphones, Speakers, Microphones |
| Wearables | wearables | Smartwatches, Fitness Trackers, Bands |
| Smart Home | smart-home | Lighting, Plugs, Sensors, Hubs |
| Cameras | cameras | Action Cams, Security, Lenses |
| Computing | computing | Laptops, Keyboards, Monitors, Storage |
| Accessories | accessories | Chargers, Cables, Cases |
All shipped icon and image paths point at SVGs under public/categories/ (for
example /categories/audio.svg). Replace these files, or point the fields at your own
assets, to re-illustrate the categories.
Rebranding checklist
Set your identity. Update name, tagline, description, and url to your
brand and production domain.
Fill in contact and social. Replace every value under contact and links with
real details — these render in the footer and contact section.
Adjust navigation. Edit mainNav and legalNav so every href points at a route
that exists in your app.
Define your catalog structure. Rewrite productCategories — set each name,
slug, description, badges, and drop matching artwork into
public/categories/. Keep slugs URL-safe; they appear in
/products?category=<slug>.
Pick currencies and locales. Set the base currency, list switchable
currencies (base first, rate: 1), and register your locales and defaultLocale
alongside their i18n dictionaries.
Choose a color scheme. Apply a theme preset — or your own triplets — to the
--brand* variables in src/app/globals.css.
None of this depends on Stripe, Resend, or a SQL backend — branding applies to the default quote-based store and does not change when you enable those later.