Shared Docusaurus config for every StackQL web property: the main site
(stackql.io), stackql-deploy, and every provider microsite
(*-provider.stackql.io).
One repo defines the header, footer, menus, presets, theme, and prism config.
Each site vendors main at build time and supplies only its own identity
(providerName, providerTitle). Sidebars stay per-site.
This module is vendored, not installed. Each site shallow-clones main into
a gitignored folder during its build, then its docusaurus.config.js imports
the createConfig factory from there.
mainis the live contract. No tags, no semver, no packages. Change onmain-> next build of each site picks it up.- The factory imports nothing external. Any installed dep it needs (currently
just
prism-react-renderer) is passed in by the site wrapper. This keeps the vendored module resolvable under every YarnnodeLinkerincluding PnP. - All cross-site nav/footer links are absolute urls to their canonical home
(
https://stackql.io/install,https://aws-provider.stackql.io, etc). A relativeto: '/install'would resolve against the rendering microsite, which has no such page. - Sidebars are per-site. Nothing in this repo touches them.
index.js- exportscreateConfig({ providerName, providerTitle, prismThemes, overrides }).README.md- this file.
Optionally (not yet added): shared static assets (custom.css, logos) and a
smoke-test CI that imports createConfig and runs docusaurus build against a
fixture site before merging to main.
One-time wiring per site.
The only file you routinely touch per site.
export const providerName = 'anthropic';
export const providerTitle = 'Anthropic';Not a prebuild hook - Yarn Berry does not run pre/post scripts. The clone
fails loudly (non-zero exit) if the repo is unreachable, which stops the build
by design. A failed build leaves the previous successful deploy live on both
Netlify and GitHub Pages, so there is no need for a committed snapshot
fallback.
Netlify (netlify.toml):
[build]
command = "rm -rf .shared-config && git clone --depth 1 --branch main https://github.com/stackql/docusaurus-config.git .shared-config && yarn build"GitHub Pages (steps in the deploy workflow, before the build):
- name: Vendor shared config
run: rm -rf .shared-config && git clone --depth 1 --branch main https://github.com/stackql/docusaurus-config.git .shared-config
- name: Build
run: yarn buildNo-git alternative for either:
curl -L https://github.com/stackql/docusaurus-config/archive/refs/heads/main.tar.gz | tar xz
mv docusaurus-config-main .shared-configimport {themes as prismThemes} from 'prism-react-renderer';
import { createConfig } from './.shared-config/index.js';
import { providerName, providerTitle } from './provider.js';
export default createConfig({ providerName, providerTitle, prismThemes });prism-react-renderer is imported in the site wrapper (where Yarn can resolve
it), not in the vendored module.
Sidebars stay per-site. Read the title from provider.js instead of reaching
into config.title and string-stripping it.
Docs are mounted at the site root (routeBasePath: '/' in the shared
preset), so the doc with id: 'provider-intro' is the page served at
https://<slug>-provider.stackql.io/.
import { providerTitle } from './provider.js';
const sidebars = {
mainSidebar: [
// `/providers` is registered by the shared redirect plugin and
// client-side-redirects to https://stackql.io/providers.
{ type: 'link', label: 'All Providers', href: '/providers' },
{
type: 'category',
label: `${providerTitle} Provider`,
link: { type: 'doc', id: 'provider-intro' },
items: [{ type: 'autogenerated', dirName: 'services' }],
},
],
};
export default sidebars;.shared-config/
createConfig accepts an overrides object that is shallow-merged on top of
the returned config. Use it for genuinely site-specific tweaks (a different
gtag ID, a different editUrl, an extra plugin). Anything you find yourself
overriding on more than one site belongs in the shared config, not in
overrides.
export default createConfig({
providerName,
providerTitle,
prismThemes,
overrides: {
onBrokenLinks: 'throw',
},
});The merge is shallow - nested objects (themeConfig, presets) are replaced
wholesale, not deep-merged. If you need to tweak something nested, copy the
whole branch into overrides, or extend the factory to accept a more specific
parameter.
Shared nav and footer items that point at the main site (Install,
stackql-deploy, Providers, Blog, Tutorials, Contact us, etc.) use
relative to: URLs. A bundled Docusaurus plugin (stackql-shared-redirects,
defined in index.js) registers a route at each of those paths in the
consumer site. Visiting /install on any microsite hits that route, which
client-side-redirects to https://stackql.io/install.
The upside of going through redirect routes rather than absolute hrefs:
- The items render without the external-link icon (Docusaurus only decorates
truly-external
href:items). - Typing
https://aws-provider.stackql.io/installdirectly into the address bar lands on the right page instead of 404ing. - The same menu config works on
stackql.ioitself (if it ever consumes this factory) - the redirect routes would no-op against the main site's actual pages.
Items that still use absolute href: (and therefore render with the
external-link icon):
- Providers dropdown items - they target other provider microsites, not the main site, so the local redirect routes don't help.
- AI Agents children - deep doc paths on the main site, not in the redirect map.
- The GitHub icon in the top right - genuinely external.
Cross-site clicks still cause full-page loads (different origins, unavoidable), and Docusaurus computes no active-state highlight for redirect routes.
A shared-repo change reaches a deployed site on that site's next build. Sites rebuild naturally on their own content pushes. To push a shared change out without editing any site repo:
- Netlify: create a build hook per site (a URL you POST to) and have a script POST all of them.
- GitHub Pages: trigger each site's Actions workflow via
workflow_dispatchorrepository_dispatch.
This is a fan-out of build triggers, not edits.
main is the live contract with no version pinning, so the safety lives in
build behavior and in guarding main.
- Fail loud, not stale. A failed clone stops the build. Previous successful deploy stays live. That is the real last-known-good - do not add a committed snapshot fallback.
- Guard
main. Every site tracks it unpinned, so a bad commit breaks the next build of every site at once. Protect the branch with PR review and a CI smoke test in this repo that importscreateConfig, invokes it, and runsdocusaurus buildagainst a fixture site before merge. A greenmainis the propagation gate. - Fresh each build. The
rm -rfbefore clone ensures the vendored copy is always currentmain, never a cached stale one.
- Central sidebars and related-provider cross-links - sidebars stay per-site.
- Runtime CSS/JS injection via a worker - reserved for instant cosmetic changes if ever needed; not part of this build-time approach.
- The stars badge worker - unrelated, stays as-is. It is runtime because its data is live; this config is build-time because it changes on human timescales.
- Land this repo on
main. Add the smoke-test CI before relying on it. - Wire one pilot provider site (steps 1-5 above). Build locally and on the platform. Confirm the header, footer, and menus render identically to before, and that the absolute cross-site links resolve to the right properties.
- Apply the same wiring to the remaining sites.
- (Optional) Set up the rebuild fan-out so shared changes go live without waiting for a content push.