Want to skip the docs? Check out pandamastery.com - the best way to learn Panda CSS

design systems
shared styled system

Shared styled-system in a monorepo

Point every app in a monorepo at one generated styled-system package instead of each one re-deriving its own.

If every package in your monorepo runs its own Panda config from scratch, each one ends up with a slightly different styled-system: its own token names, its own recipe definitions, sometimes its own drift when one app updates a token and the others don't. The fix is the same one you'd use for an external component library: one package owns the design system, everyone else imports from it.

This is the internal version of that setup. There's no npm publish step and no external users to keep a stable API for, just a workspace dependency and importMap so each app's own Panda instance recognizes the shared package's imports during extraction.

Point every app at one shared package

Give the design system its own workspace package, the same way Set up a library package describes, then have each app depend on it and set importMap to match:

pnpm add @acme/styled-system --workspace

apps/marketing/panda.config.ts

import { defineConfig } from '@pandacss/dev'
 
export default defineConfig({
  //...
  presets: ['@acme/styled-system/preset'],
  importMap: '@acme/styled-system',
  include: ['./src/**/*.{ts,tsx}']
})

presets pulls in the shared tokens and recipe definitions so the app's own generated types match. importMap tells the app's parser that import { css } from '@acme/styled-system/css' is a style call, not an arbitrary function, so extraction and codegen work against the shared runtime instead of assuming a locally-declared one. Each app still runs its own panda codegen, since it still needs to extract its own source and generate CSS tailored to what it actually uses, it just isn't redefining the design system's tokens and recipes to do it.

Adding a local overlay

Some apps need a few recipes or patterns of their own on top of the shared set, without forking the shared package. importMap accepts more than one root, so you can point extraction at both the shared package and the app's own local styled-system output in one go:

apps/marketing/panda.config.ts

import { defineConfig } from '@pandacss/dev'
 
export default defineConfig({
  //...
  presets: ['@acme/styled-system/preset'],
  importMap: ['@acme/styled-system', './styled-system'],
  outdir: 'styled-system'
})

Extraction now recognizes imports from either root. Shared components import css/cva from @acme/styled-system as before; anything defined only in this app imports from its own local ./styled-system output. importMap also accepts an object form when different categories (css, recipes, patterns, jsx, tokens) need different roots, for example if the shared package owns tokens and recipes but every app generates its own local patterns:

importMap: {
  css: ['@acme/styled-system/css', './styled-system/css'],
  recipes: '@acme/styled-system/recipes',
  patterns: './styled-system/patterns'
}

See importMap for the full set of accepted shapes.

Using designSystem instead

designSystem: '@acme/styled-system' does the presets plus importMap wiring for you, and hydrates the package's build info so the app does not re-extract library source. See Consume a design system. The setup on this page still works if the shared package does not ship a panda lib manifest.

See also