Migrating from Panda CSS
Migrate your project from Panda CSS to Bamboo CSS.
Bamboo CSS started as a fork of Panda CSS (opens in a new tab), so unlike the other guides in this section this one is not a rewrite. The styling API is the same: your style objects, recipes, patterns, conditions and tokens carry over unchanged. What changes is the name of the package they come from.
For most projects this is a find-and-replace of panda with bamboo, plus a re-run of codegen.
What stays the same
css,cva,sva,cxand the pattern functions – same names and authoring signatures. Under Vite they are compile-time APIs: recipe selections share the same global declaration atoms ascss()(below).- Recipes, variants, compound variants and default variants. Slot recipes are the exception – their output compiles to one atom string per selected slot; see below.
- Tokens, semantic tokens, conditions, breakpoints, themes,
staticCss, cascade layers. - The config shape, minus five keys. Every key you have in
panda.config.tsis valid inbamboo.config.tsexceptstudio,jsxFramework,jsxFactory,jsxStylePropsandsyntax, none of which have an equivalent – delete them. - The output directory. It still defaults to
styled-system, so imports likestyled-system/cssdo not move.
Because the generated output directory keeps its name and shape, the only imports you have to touch are the ones that
name the tool itself – the config file, and any direct @pandacss/* imports. Replace @pandacss/postcss with
@bamboocss/vite.
Rename the packages
Every package moves from the @pandacss scope to @bamboocss. The ones a project normally depends on:
| Panda CSS | Bamboo CSS |
|---|---|
@pandacss/dev | @bamboocss/dev |
@pandacss/types | @bamboocss/types |
@pandacss/preset-base | @bamboocss/preset-base |
@pandacss/preset-panda | @bamboocss/preset-bamboo |
@pandacss/postcss | @bamboocss/vite |
The internal packages (@pandacss/core, /node, /parser, /generator, /token-dictionary and the rest) follow the
same rule if you import them directly.
The default preset is the one rename that is not a straight scope swap: @pandacss/preset-panda becomes
@bamboocss/preset-bamboo. If you never listed presets explicitly, the defaults are applied for you and there is
nothing to change.
Step by step
Swap the dependencies
Rename the config file
panda.config.ts becomes bamboo.config.ts. Bamboo looks for bamboo.config.{ts,js,mts,mjs} and will not pick up a
file under the old name.
Update the import inside it, and the preset names if you listed them:
bamboo.config.ts
import { defineConfig } from '@bamboocss/dev'
export default defineConfig({
presets: ['@bamboocss/preset-base', '@bamboocss/preset-bamboo'],
include: ['./src/**/*.{js,jsx,ts,tsx}'],
outdir: 'styled-system',
})Use the Vite plugin
Delete the @pandacss/postcss entry. Add bamboocss() from @bamboocss/vite and import virtual:bamboo.css. See
Using Vite.
Update your scripts
The CLI is bamboo (bamboocss also works). Every command keeps its name, so panda codegen becomes bamboo codegen,
panda cssgen becomes bamboo cssgen, and so on.
{
"scripts": {
"prepare": "bamboo codegen"
}
}Regenerate the output directory
Delete the existing styled-system directory and generate it again, so nothing from the previous install is left
behind:
rm -rf styled-system
pnpm bamboo codegencx joins, in both tools
At runtime, both helpers join arbitrary class strings. Bamboo's Vite compiler additionally recognizes analyzable Bamboo
style arguments: it composes their declarations in argument order before allocating atoms, so overridden declarations do
not ship. A cx() containing an unknown external class remains the tiny joining helper. See
Merging styles.
Vite compiles slot selections directly
Panda's slot recipe output carries recipe- and variant-specific classes. Bamboo's Vite compiler resolves the selection first, then returns one shared atom string per slot:
const classes = checkbox({ size })
return (
<div className={classes.root}>
<span className={classes.label} />
</div>
)
A static selection becomes a literal object. A finite runtime selection becomes a reduced lookup whose leaves are
complete slot objects. Recipe names, slot names, scopeRoots, and DOM shape do not enter the emitted selectors, so
portals require no CSS scoping accommodation. Use a stable data-slot attribute if application CSS or tests need a
semantic slot selector; generated atom names are intentionally opaque.
Vite compiles recipes to shared atoms
With @bamboocss/vite, cva() and sva() are compile-time declarations. A selected recipe is resolved to authored
styles and shares declaration atoms with every other recipe and css() call:
cva({ base: { padding: '4' }, variants: { size: { sm: { fontSize: 'sm' } } } })
// panda: 'p_4 fs_sm'
// bamboo: compact global atoms for padding:4 and fontSize:sm
The recipe name, source file, and className do not enter declaration identity. For analyzable cx(recipe(), css()),
Bamboo composes the StyleSets in argument order before allocating classes, so overrides do not depend on stylesheet
order.
Finite runtime axes become a reduced lookup whose leaves already include matching compound variants. The recipe config and recipe-specific selectors do not ship. Bamboo has no extraction-only runtime recipe mode.
Things that are easy to miss
-
PANDA_DEBUGis nowBAMBOO_DEBUG. See Debugging. -
There is no JSX factory.
styled.div,panda.div,styled('button', recipe),createStyleContextandsplitCssPropshave no equivalent, andstyled-system/jsxis not generated at all. Style props become acss()call, and a recipe component becomes an ordinary component that calls the recipe:// panda const Button = styled('button', buttonRecipe) <Button size="sm" /> // bamboo const Button = (props: ButtonProps) => { const [variantProps, rest] = buttonRecipe.splitVariantProps(props) return <button {...rest} className={cx(buttonRecipe(variantProps), props.className)} /> }jsxFramework,jsxFactoryandjsxStylePropsare gone from the config with it — delete them.createStyleContextwrapped each slot in a component so it could see the root's variant. A slot recipe returns a record of class strings, so a compound component carries that record in an ordinary context and needs no wrapper per part — see styling compound components. -
There are no JSX pattern components.
<Stack>,<Box>,<HStack>and the rest are not generated, andstyled-system/jsxdoes not exist to import them from. The pattern functions are unchanged and are what those components wrapped, so the rewrite is mechanical:// panda import { Stack } from '../styled-system/jsx' ;<Stack gap="4" align="center"> {children} </Stack> // bamboo import { flex } from '../styled-system/patterns' ;<div className={flex({ direction: 'column', gap: '4', align: 'center' })}>{children}</div> -
There is no template literal syntax.
css`color: red`, and the template form ofcva,svaand the patterns, are not supported. Write the object form:// panda const heading = css` font-size: 24px; font-weight: bold; ` // bamboo const heading = css({ fontSize: '24px', fontWeight: 'bold' })The
syntaxconfig key is gone with it — both values — so delete it if you set it either way. -
The ESLint plugin is
@bamboocss/eslint-plugin. -
Editor and CI caches. The TypeScript server holds on to the old
styled-systemtypes; restart it after regenerating. -
.gitignore. If you generatestyled-systemin CI rather than committing it, the entry does not change, since the directory name is the same.
Worth a look once you have migrated
These are documented in full elsewhere, and none of them are required to get a migrated project building:
- Source compilation –
@bamboocss/viteresolves every style API into shared atoms or a finite recipe table, and rejects open runtime styling. prune.tokens– drops token CSS variables nothing can reach, which is usually the largest single saving in render-blocking CSS. On by default.preflight.prune– drops the parts of the reset that style elements your source never renders, which is most of what is left once the tokens have gone. Off by default, and the one pruning option that cannot be proven from the build.- Spec files – generate a machine-readable description of your design system.
- MCP server and llms.txt – expose your design system to AI tooling.
Getting help
If something does not carry over, check the open issues (opens in a new tab) first. If you cannot find it, please open a new issue (opens in a new tab) with a minimal reproduction.