Make utility-first CSS render faster — 50% faster style recalculation, 42% faster First Paint
Classpresso consolidates repeated utility class patterns at build time, dramatically reducing browser rendering work. Works with Tailwind, Bootstrap, Bulma, Tachyons, UnoCSS, and any utility-first CSS framework.
📦 Post-Build Tool — Your Development Workflow is Unchanged
Classpresso runs after your build (
npm run build), not during development. Your source code is never modified — only the compiled output in.next,dist,build, etc. You'll always see your normal Tailwind/utility classes while developing and debugging.
| Metric | Improvement |
|---|---|
| Style Recalculation | 50% faster |
| First Paint | 42% faster |
| Memory Usage | 21% less |
| Runtime Overhead | 0ms |
Benchmarks run on 1000 complex components with Playwright + Chrome DevTools Protocol
Utility-first CSS means elements with 10-20+ classes:
<button class="inline-flex items-center justify-center rounded-md text-sm font-medium
transition-colors focus-visible:outline-none focus-visible:ring-2
bg-primary text-white hover:bg-primary/90 h-10 px-4 py-2">
Submit
</button>
Every class on every element is work for the browser: - Parse the class string - Look up each class in stylesheets - Calculate specificity and resolve conflicts - Compute final styles
With 15 classes × 500 elements = 7,500 class lookups per page load.
Classpresso finds repeated patterns and consolidates them:
Before:
<button class="inline-flex items-center justify-center rounded-md text-sm font-medium...">Submit</button>
<button class="inline-flex items-center justify-center rounded-md text-sm font-medium...">Cancel</button>
<button class="inline-flex items-center justify-center rounded-md text-sm font-medium...">Delete</button>
After:
<button class="cp-btn bg-primary">Submit</button>
<button class="cp-btn bg-secondary">Cancel</button>
<button class="cp-btn bg-destructive">Delete</button>
Generated CSS:
.cp-btn {
display: inline-flex;
align-items: center;
justify-content: center;
/* ... all consolidated utilities */
}
Result: Fewer classes = less browser work = faster rendering.
npm install classpresso --save-dev
# Build your project first
npm run build
# Analyze potential savings (auto-detects build directory)
npx classpresso analyze
# Apply optimizations
npx classpresso optimize
Classpresso auto-detects your build directory (.next, dist, build, .output, etc.), so you usually don't need to specify --dir.
| Framework | Classes per Element | Performance Gain |
|---|---|---|
| Tailwind CSS | 10-20+ typical | Excellent |
| Bootstrap | 5-15 typical | Good |
| Bulma | 5-10 typical | Good |
| Tachyons | 15-25+ typical | Excellent |
| UnoCSS | 10-20+ typical | Excellent |
| Any utility CSS | Varies | Automatic |
Classpresso works with 20+ frameworks out of the box:
| Framework | Build Directory | SSR Flag | Notes |
|---|---|---|---|
| React Meta-Frameworks | |||
| Next.js | .next (default) |
--ssr for App Router |
Pages Router usually doesn't need SSR flag |
| Remix | build |
--ssr recommended |
|
| Gatsby | public |
Not needed | Static only |
| RedwoodJS | web/dist |
--ssr if using SSR |
|
| Vue Meta-Frameworks | |||
| Nuxt 3 | .output |
--ssr recommended |
|
| VitePress | .vitepress/dist |
Not needed | Static docs |
| Gridsome | dist |
Not needed | Static only |
| Svelte | |||
| SvelteKit | build |
--ssr recommended |
Or .svelte-kit |
| Other Frameworks | |||
| Astro | dist |
--ssr for islands |
Static doesn't need SSR |
| Solid Start | .output or dist |
--ssr recommended |
|
| Qwik | dist |
--ssr recommended |
|
| Angular | dist/[project-name] |
Not needed | Angular 17+ uses browser/ subdir |
| Ember | dist |
Not needed | |
| Preact | build or dist |
Depends on setup | |
| Generic Bundlers | |||
| Vite | dist |
Depends on framework | |
| Webpack | dist |
Not needed | |
| Parcel | dist |
Not needed | |
| Create React App | build |
Not needed | |
| Static Site Generators | |||
| Eleventy (11ty) | _site |
Not needed | |
| Hugo | public |
Not needed | |
| Docusaurus | build |
Not needed |
Zero code changes required. Classpresso runs on your build output. Your React, Vue, Svelte, Solid, Qwik, Astro, Angular, or vanilla HTML stays exactly the same.
1. You run your normal build (next build, vite build, etc.)
2. Classpresso scans the output:
→ Finds all class attributes
→ Identifies patterns that repeat
→ Calculates which are worth consolidating
3. Classpresso transforms:
→ Replaces repeated patterns with short hash classes
→ Generates CSS that maps hashes to original utilities
→ Updates HTML/JS with new class names
4. Result:
→ Same visual appearance
→ Dramatically fewer class lookups
→ Faster style recalculation on every interaction
All commands auto-detect your build directory. You can override with --dir if needed.
classpresso analyzeAnalyze build output and show potential optimizations without modifying files.
classpresso analyze # Auto-detects build dir
classpresso analyze --dir dist # Explicit build dir
classpresso analyze --min-occurrences 3 --min-classes 3
classpresso analyze --json
Options:
- -d, --dir <path> - Build directory (auto-detected if not specified)
- --min-occurrences <n> - Minimum times a pattern must appear (default: 2)
- --min-classes <n> - Minimum classes in a pattern (default: 2)
- --ssr - Enable SSR-safe mode for hydration compatibility
- --json - Output as JSON
- -v, --verbose - Verbose output
- --debug - Generate detailed debug log file for troubleshooting
- --send-error-reports - Send error reports to configured webhook
- --error-report-url <url> - Webhook URL for error reports
classpresso optimizeApply optimizations to the build output.
classpresso optimize # Auto-detects build dir
classpresso optimize --dir .next # Explicit build dir
classpresso optimize --dry-run
classpresso optimize --backup
classpresso optimize --purge-unused # Also remove unused CSS
Options:
- -d, --dir <path> - Build directory (auto-detected if not specified)
- --min-occurrences <n> - Minimum times a pattern must appear (default: 2)
- --min-classes <n> - Minimum classes in a pattern (default: 2)
- --ssr - Enable SSR-safe mode for hydration compatibility
- --dry-run - Show what would be done without making changes
- --backup - Create backup files before modifying
- --no-manifest - Don't generate manifest file
- --purge-unused - Remove unused CSS classes after consolidation
- --no-rehash - Don't re-hash content-hashed assets (see Content-Hashed Assets below)
- -v, --verbose - Verbose output
- --debug - Generate detailed debug log file for troubleshooting
- --send-error-reports - Send error reports to configured webhook
- --error-report-url <url> - Webhook URL for error reports
Bundlers like Vite, Rollup, and webpack name output files after a hash of their content (index-a1b2c3d4.css), and those files are usually served with Cache-Control: immutable for long-term caching. Because optimize rewrites files in place, the served content changes while the filename hash does not - so a returning browser keeps serving the stale cached copy after a redeploy, breaking styling.
To prevent this, optimize re-hashes every content-hashed asset it modifies: the file is renamed to a new content-hash filename and every reference to it (HTML, JS, CSS url(), bundler manifests) is rewritten. The naming is deterministic, so identical input produces identical output. This is on by default and only renames files whose names already look like content hashes; stable names like styles.css are never touched.
Pass --no-rehash to keep the original filenames (for example, if you run optimize before the bundler applies its hashing step).
classpresso validateCheck for hydration safety issues before optimizing. Catches potential React/Vue/Svelte hydration mismatches.
classpresso validate # Auto-detects build dir
classpresso validate --dir .next
classpresso validate --json
Example output:
☕ Classpresso - Hydration Safety Validator
📊 Hydration Safety Summary
Patterns analyzed: 22
Hydration-safe: 17
Server-only: 3
Client-only: 2
Mergeable (props): 1
⚠️ Found 5 patterns that may cause hydration issues:
1. "flex items-center gap-4"
Status: SERVER-ONLY
Location: server/page.html:47
Fix: This pattern only appears in server-rendered HTML...
💡 Recommendations
⚠️ Mixed server/client patterns detected.
Use "classpresso optimize --ssr" to only consolidate safe patterns.
Options:
- -d, --dir <path> - Build directory (auto-detected if not specified)
- --json - Output as JSON
- -v, --verbose - Verbose output
- --debug - Generate detailed debug log file for troubleshooting
classpresso unusedAnalyze CSS for unused classes. Find dead CSS that can be removed.
classpresso unused # Auto-detects build dir
classpresso unused --dir dist
classpresso unused --verbose # Show file breakdown
classpresso unused --json
Example output:
☕ Classpresso - Unused CSS Analyzer
📊 Summary
CSS files scanned: 3
Total CSS rules: 1,247
Classes used: 892
Classes unused: 47
💾 Size Impact
Unused CSS bytes: 12,340 (12.1 KB)
Gzip estimate: 3,120 (3.0 KB)
🔝 Top 10 Unused Classes (by size)
1. hover\:bg-gradient-to-r 234 B
2. focus\:ring-offset-4 189 B
...
💡 Recommendations
⚠️ Found 12.1 KB of unused CSS.
Run "classpresso optimize --purge-unused" to remove these classes.
Options:
- -d, --dir <path> - Build directory (auto-detected if not specified)
- --limit <n> - Number of top unused classes to show (default: 20)
- --json - Output as JSON
- -v, --verbose - Verbose output (show file breakdown)
- --debug - Generate detailed debug log file for troubleshooting
classpresso reportGenerate a report from an existing manifest.
classpresso report # Auto-detects build dir
classpresso report --dir .next
classpresso report --format json
classpresso report --format html > report.html
Options:
- -d, --dir <path> - Build directory (auto-detected if not specified)
- --format <type> - Output format: text, json, html (default: text)
With auto-detection, most integrations are now simpler:
{
"scripts": {
"build": "next build && classpresso optimize --ssr",
"build:analyze": "next build && classpresso analyze"
}
}
{
"scripts": {
"build": "vite build && classpresso optimize"
}
}
Classpresso auto-detects dist, build, or your framework's output directory.
Classpresso fully supports Astro static, SSR, and hybrid builds.
Static Build (default):
{
"scripts": {
"build": "astro build && classpresso optimize --dir dist"
}
}
SSR/Hybrid Build (with React/Vue/Svelte islands):
{
"scripts": {
"build": "astro build && classpresso optimize --dir dist --ssr"
}
}
Configuration file:
// classpresso.config.js
module.exports = {
buildDir: 'dist',
// Use --ssr flag if you have interactive islands with client:* directives
ssr: false,
};
Classpresso automatically detects Astro's build structure:
- dist/**/*.html - Static HTML pages
- dist/_astro/**/*.js - Client-side JavaScript
- dist/_astro/**/*.css - Compiled CSS
- dist/server/**/*.mjs - Server code (SSR mode)
- dist/client/_astro/**/* - Client assets (SSR mode)
{
"scripts": {
"build": "nuxt build && classpresso optimize --dir .output --ssr"
}
}
{
"scripts": {
"build": "vite build && classpresso optimize --dir build --ssr"
}
}
{
"scripts": {
"build": "remix build && classpresso optimize --dir build --ssr"
}
}
{
"scripts": {
"build": "vinxi build && classpresso optimize --dir .output --ssr"
}
}
{
"scripts": {
"build": "qwik build && classpresso optimize --dir dist --ssr"
}
}
{
"scripts": {
"build": "ng build && classpresso optimize --dir dist/my-app"
}
}
For Angular 17+, the output is in dist/[project-name]/browser.
{
"scripts": {
"build": "gatsby build && classpresso optimize --dir public"
}
}
{
"scripts": {
"build": "eleventy && classpresso optimize --dir _site"
}
}
hugo && classpresso optimize --dir public
{
"scripts": {
"build": "docusaurus build && classpresso optimize --dir build"
}
}
{
"scripts": {
"build": "vitepress build && classpresso optimize --dir .vitepress/dist"
}
}
For *
$ claude mcp add classpresso \
-- python -m otcore.mcp_server <graph>