# The midcode package

> Build midcode.css without the app, in your production build, in CI or beside an agent, with the midcode CLI, its Vite plugin or its Next.js wrapper.

- Page: https://midcode.app/docs/styling/package
- From the midcode docs. Every page as Markdown: https://midcode.app/llms.txt

In a project [without Tailwind 4](https://midcode.app/docs/styling/without-tailwind.md), your styles are `mid:` classes in the code, and `midcode.css` is their CSS. The app rewrites that file while the project is open in it. The `midcode` package does the same job everywhere else: a command line tool, a Vite plugin and a Next.js wrapper that build `midcode.css` from the classes in your code.

A project that uses Tailwind 4 doesn't need it: there, midcode writes Tailwind's own classes and Tailwind compiles them.

## When you need it

`midcode.css` is a plain file in your repository, so a site that was only ever edited in midcode builds and deploys with nothing added. Add the package when the classes can change while the app isn't looking:

- You or an agent write `mid:` classes by hand, in an editor or a terminal.
- You want the file rebuilt in CI or in your production build, so that it can never be out of date.
- You'd rather not commit a generated file, and build it instead. Then always pass `--out`, so that a fresh checkout knows where the file goes.
- A teammate works on the project without midcode.

## Install

```bash
npm install -D midcode
pnpm add -D midcode
yarn add -D midcode
```

It needs Node 20 or later. Its one dependency is `tailwindcss` (version 4), which it uses as the compiler for `mid:` classes. Your own stylesheets don't go through Tailwind and nothing in your build config changes unless you add one of the integrations below.

## Any project: the command

Run it before your build, or leave it watching while you work:

```json title="package.json"
{
  "scripts": {
    "prebuild": "midcode",
    "dev:css": "midcode --watch"
  }
}
```

| Command | What it does |
| --- | --- |
| `midcode` | Builds `midcode.css` once. |
| `midcode --watch` | Builds it, and again whenever your code or your theme changes. `-w` for short. |
| `--root <dir>` | The project's folder. Default: the current one. |
| `--out <file>` | Where `midcode.css` goes when the project has none yet. |
| `--help` | Prints the options. `-h` for short. |

A build prints one line:

```bash
$ npx midcode
midcode: 42 classes → /Users/you/site/app/midcode.css
```

It adds "(up to date)" when the file didn't need to change. On an error it prints `midcode: <message>` and exits with code 1, so a `prebuild` script stops the build.

Where your package manager doesn't run `pre` scripts by itself (Yarn 2 and later), call it in the script: `"build": "midcode && vite build"`.

## Vite, Astro, SvelteKit, React Router, Remix

Add the plugin and `midcode.css` is built when the dev server or a build starts, and again whenever a source file or the theme is added, changed or removed while the dev server runs.

```ts title="vite.config.ts"
import { defineConfig } from 'vite'
import midcode from 'midcode/vite'

export default defineConfig({ plugins: [midcode()] })
```

The project's folder is Vite's own `root`. Pass `midcode({ root, out })` to change it, with the same meaning as the command's options.

## Next.js

Wrap your config. `midcode.css` is built before Next starts, and kept up to date while `next dev` runs.

```ts title="next.config.ts"
import withMidcode from 'midcode/next'

export default withMidcode({
  // your config
})
```

`withMidcode` takes your config as an object or as a function, and options as a second argument: `withMidcode(config, { root, out })`. If the build of `midcode.css` fails, it prints the error and lets Next go on.

## From code

The same two functions the command uses are exported:

```ts
import { build, watch } from 'midcode'

const result = await build({ root: process.cwd() })
// { file: '/abs/path/midcode.css', classes: 42, changed: true }

const stop = await watch({}, (r) => {
  if (r instanceof Error) console.error(r.message)
})
```

## Starting without the app

The package always writes to the `midcode.css` the project already has, wherever it is. In a project that has none, say where it goes and import it in your entry:

```bash
npx midcode --out src/midcode.css
```

```ts title="src/main.tsx"
import './midcode.css'
```

Without `--out`, and with no `midcode.css` in the project, the command stops: "No midcode.css in /Users/you/site. Pass where it goes (--out src/midcode.css) and import it in your app's entry."

From then on, write classes with the prefix first and run the command:

```html
<h1 class="title mid:text-[80px] mid:md:text-[56px] mid:hover:text-[#ff5b2e]">Hello</h1>
```

Tokens go in `.midcode/theme.css`. See [Theme and design tokens](https://midcode.app/docs/styling/theme.md) for the format.

```css title=".midcode/theme.css"
@theme {
  --color-brand: #ff5b2e;        /* mid:bg-brand, mid:text-brand */
  --font-display: "Fraunces";    /* mid:font-display */
}

@utility lead {                  /* mid:lead, mid:md:lead */
  font-size: 20px;
  line-height: 1.5;
}
```

When you open that project in midcode later, it reads the same classes and the same theme and carries on from there. Put the file where the app looks for it: next to your entry, or in `src/`, `app/`, `src/app/`, `src/routes/` or the project's root.

## What it reads

- **Classes**: every `mid:` class in the project's `.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs`, `.svelte`, `.astro`, `.vue`, `.html`, `.md` and `.mdx` files. It skips `node_modules`, `.git`, `.next`, `.nuxt`, `.svelte-kit`, `.astro`, `.vercel`, `.turbo`, `.cache`, `dist`, `build`, `out` and `coverage`.
- **The theme**: `.midcode/theme.css`, when there is one.
- **The output**: the first `midcode.css` it finds in the project. That file is rewritten whole, and only when its content would change.

What it writes is the same CSS the app writes: one rule per class, every declaration `!important`, in layers named `mid-theme` and `mid-utilities`, followed by the reset scoped to `mid-base`. The full description is in [Without Tailwind](https://midcode.app/docs/styling/without-tailwind.md).

> [!WARNING]
> Commit `.midcode/theme.css` if you build `midcode.css` anywhere but your Mac. The package reads your colors, fonts and text styles from it. Without it, classes like `mid:bg-brand` and `mid:lead` get no CSS. In [Publish](https://midcode.app/docs/publish/publish.md), files under `.midcode/` are listed but not ticked: tick this one.

## Limits

- The command and the integrations build the stylesheet. They don't add the import to your entry and they don't write classes: that's the app, or you.
- A class name put together at runtime (`'mid:p-' + size`) isn't found. Write classes out whole.
- Version 0.1.0 doesn't read server templates (`.php`, `.erb`, `.liquid`, `.twig` and the like). The app reads them from its next release.
- If the project has more than one `midcode.css`, only the first one found is written.
