Version 0.2.0 released! Check out the release notes from GitHub Releases

defineConfig for Next.js — Set Up Tokens, Modifiers, and Strict Mode Once for Server and Client

defineConfig for the Next.js App Router

defineConfig is the entry point for your project's Salty CSS configuration. It accepts a single config object and returns it unchanged — its only job is to give you TypeScript inference for every field. The file is conventionally named salty.config.ts and lives next to your bundler config (next.config.ts, vite.config.ts, astro.config.mjs).

For per-feature deep dives see the linked pages; this page is the single-stop reference.

Import

import { defineConfig } from "@salty-css/react/config";

The shape is the same across all framework subpaths — pick whichever matches your runtime.

Minimal config

A blank config is valid; Salty CSS will use defaults for everything:

// /salty.config.ts
import { defineConfig } from "@salty-css/react/config";

export const config = defineConfig({});

Full reference

defineConfig({
  variables?: SaltyVariables,
  global?: GlobalStyles,
  reset?: 'default' | 'none' | GlobalStyles,
  templates?: CssTemplates,
  modifiers?: CssModifiers,
  importStrategy?: 'root' | 'component',
  externalModules?: string[],
  strict?: boolean | 'warn',
  defaultUnit?: 'px' | 'rem' | 'em' | 'vh' | 'vw' | string,
})

variables

Design tokens applied to :root. Identical to passing the same object to defineVariables in a .css.ts file — use whichever fits your project layout. Tokens defined here become reachable from every style with {token.path} syntax.

defineConfig({
  variables: {
    colors: { brand: { main: "#0070f3" } },
    spacing: { small: "8px", large: "32px" },
  },
});

For responsive and conditional tokens (responsive: { ... }, conditional: { ... }), see Variables.

global

Styles applied to bare HTML selectors (html, body, a, etc.). Same shape as defineGlobalStyles.

defineConfig({
  global: {
    html: { fontFamily: "var(--font-family-main, sans-serif)" },
    body: { margin: 0 },
    a: { color: "currentcolor" },
  },
});

reset

Controls the built-in CSS reset.

ValueBehaviour
'default'Salty CSS's built-in reset is applied. (Default if omitted.)
'none'No reset — useful when you import a third-party reset yourself.
GlobalStylesA custom reset object — same shape as global.
defineConfig({ reset: "none" });
defineConfig({
  reset: {
    "*": { boxSizing: "border-box" },
    "body, html": { margin: 0, padding: 0 },
  },
});

templates

Reusable style bundles. Identical to passing the same object to defineTemplates.

defineConfig({
  templates: {
    textStyle: {
      body: { fontSize: "16px", lineHeight: "1.5" },
      heading: { fontSize: "32px", fontWeight: 700 },
    },
  },
});

modifiers

Custom value transformers — pattern + transform function. Use them when you want a shorthand syntax that Salty rewrites into real CSS at build time (e.g. a px → rem modifier or a token-shorthand). Full guide: Modifiers.

defineConfig({
  modifiers: {
    pxToRem: {
      pattern: /^(\d+)px$/,
      transform: (match) => ({ value: `${Number(match.match(/\d+/))/16}rem` }),
    },
  },
});

importStrategy

Where the generated CSS is imported from at runtime.

ValueBehaviour
'root'One stylesheet imported once at the app root. Smaller per-route HTML, larger initial CSS. (Default.)
'component'A per-component stylesheet is imported alongside the module. Better for code-splitting and route-level CSS, slightly more <link> tags.
defineConfig({ importStrategy: "component" });

externalModules

Package names that should not be bundled when Salty CSS imports your .css.ts files at build time. Useful when a third-party module pulls in something that doesn't run in Node (browser globals, native modules) but you still want it imported in the same file.

defineConfig({
  externalModules: ["react", "react-dom", "some-browser-only-lib"],
});

react and react-dom are already marked external by Salty's own internals; list them explicitly only if you've overridden them.

strict

How the parser reacts to suspicious input — typos in token references, malformed selectors, unknown CSS properties, etc.

ValueBehaviour
trueThrow on issues. Recommended for new projects — catches bugs at build time.
'warn'Log a warning and continue. Useful when migrating an existing codebase.
false / omittedSilent. Matches pre-strict behaviour.
defineConfig({ strict: true });

defaultUnit

Default unit for numeric values on px-style properties (width, padding, font-size, etc.). When you write padding: 16, Salty CSS appends the unit you set here.

Accepts: 'px' (default), 'rem', 'em', 'vh', 'vw', 'vmin', 'vmax', 'cm', 'mm', 'in', 'pt', 'pc', 'ch', 'ex', 'fr', 'percent', `viewport-clamp:${number}`, or any custom string.

defineConfig({ defaultUnit: "rem" });

The viewport-clamp:<size> form turns bare numbers into clamp() expressions against the given reference width — handy for fluid type without per-property viewportClamp() calls.

Putting it all together

A realistic config with most options set:

// /salty.config.ts
import { defineConfig } from "@salty-css/core/config";

export const config = defineConfig({
  importStrategy: "root",
  strict: true,
  defaultUnit: "px",

  variables: {
    colors: {
      brand: { main: "#0070f3", muted: "#6699cc" },
      neutral: { white: "#f0f0f0", black: "#0a0a0a" },
    },
    spacing: { small: "8px", medium: "16px", large: "32px" },

    conditional: {
      theme: {
        dark: { background: "{colors.neutral.black}", color: "{colors.neutral.white}" },
        light: { background: "{colors.neutral.white}", color: "{colors.neutral.black}" },
      },
    },
  },

  global: {
    body: { margin: 0, fontFamily: "var(--font-family-main, sans-serif)" },
    a: { color: "currentcolor" },
  },

  templates: {
    textStyle: {
      body: { fontSize: "16px", lineHeight: "1.5" },
      heading: { fontSize: "32px", fontWeight: 700, lineHeight: "1.2" },
    },
  },

  externalModules: ["react", "react-dom"],
});

Where else can these options live?

Several keys are intentionally also exposed as standalone factories — pass them via the config object, declare them in a .css.ts file, or both. Salty CSS merges:

defineConfig keyStandalone factory
variablesdefineVariables
globaldefineGlobalStyles
templatesdefineTemplates

Media queries live exclusively in *.css.ts files via defineMediaQuery — there's no mediaQueries key on the config.

See also