Tailwind CSS 55 🎨 Upgrading from Legacy Tailwind Configurations to Modern CSS-First Standards (@tailwindcss/upgrade)
Tailwind CSS v4 is not an incremental release. It is a rewrite of the framework’s engine, configuration model, and utility system. The JavaScript configuration file that defined every project’s theme since v1 is no longer auto-detected. The three @tailwind directives that anchored every stylesheet are gone. Several utility names have changed, default colors have shifted, and the plugin API has been replaced. For a project with thousands of utility classes and a complex tailwind.config.js, a manual migration is a multi-day effort. The @tailwindcss/upgrade tool exists to automate most of that work, migrating configuration to CSS, renaming utilities across templates, and updating dependencies. Understanding what the tool does, what it cannot do, and how to verify its output is the difference between a smooth upgrade and a broken stylesheet.
Key point: The upgrade tool handles the mechanical migration, but it cannot understand your project’s intent. Complex plugin configurations, dynamic theme values, and custom variant functions require manual attention. Always run the tool on a clean git branch and review every change before committing.
Why the upgrade is structural
The configuration model changed. In v3, the tailwind.config.js file was the single source of truth for theme values, plugins, content paths, and variants. In v4, configuration moves into the CSS file using the @theme directive. Custom utilities use @utility. Custom variants use @custom-variant. The JavaScript config is no longer auto-detected; a project with a tailwind.config.js and no migration will build with default Tailwind, silently ignoring all customizations.
The directives changed. The three @tailwind base, @tailwind components, and @tailwind utilities directives are replaced by a single @import "tailwindcss" statement. The @layer at-rule is no longer hijacked by Tailwind; it uses native CSS cascade layers. Custom utilities written in @layer utilities do not work as true utilities in v4 and must be converted to @utility.
The utility taxonomy changed. Several utilities were renamed for scale consistency. shadow-sm becomes shadow-xs, shadow becomes shadow-sm, rounded-sm becomes rounded-xs, blur-sm becomes blur-xs, and outline-none becomes outline-hidden. The ring utility now defaults to 1px instead of 3px, and the old 3px behavior requires ring-3.
The color system changed. Borders and dividers now default to currentColor instead of gray-200. The default color palette uses OKLCH instead of HSL. Opacity utilities like bg-opacity-50 are replaced by slash syntax like bg-black/50.
The plugin system changed. The PostCSS plugin moved from tailwindcss to @tailwindcss/postcss. Autoprefixer is no longer needed because v4 handles prefixing internally. postcss-import is also redundant because v4 resolves imports itself. Custom variants registered via addVariant() are replaced by @custom-variant.
a. Running the upgrade tool
The upgrade tool is a one-shot command that modifies the project’s files. It must be run on a clean working tree so that any unwanted changes can be reviewed and reverted.
The command
npx @tailwindcss/upgrade
The tool requires Node.js 20 or higher. It should be run from the project root, where the package.json and tailwind.config.js live.
What the tool does
The tool performs five categories of change. First, it updates dependencies: tailwindcss, @tailwindcss/postcss, @tailwindcss/vite, @tailwindcss/cli, and prettier-plugin-tailwindcss are bumped to v4. Second, it migrates CSS files: @tailwind directives become @import "tailwindcss", @layer utilities blocks become @utility definitions, and @apply statements are updated to use renamed classes. Third, it converts tailwind.config.js to CSS: theme values become @theme entries, custom variants become @custom-variant, and plugin configurations become @plugin directives. Fourth, it updates template files: renamed utilities are replaced, arbitrary values are canonicalized, and variant order is normalized. Fifth, it updates the PostCSS configuration and removes autoprefixer.
The dry-run limitation
The tool does not have a dry-run mode. It modifies files in place. The only safety mechanism is version control. Before running the command, the working tree should be clean. After running, git diff shows every change the tool made, and any unwanted change can be reverted individually.
git checkout -b upgrade-tailwind-v4
npx @tailwindcss/upgrade
git diff
The PostCSS configuration update
For a PostCSS-based project, the tool replaces the tailwindcss plugin with @tailwindcss/postcss and removes autoprefixer and postcss-import. The new configuration is minimal.
// postcss.config.js (after upgrade)
module.exports = {
plugins: {
'@tailwindcss/postcss': {},
},
};
For a Vite project, the tool installs @tailwindcss/vite and updates the Vite configuration. The PostCSS config can be removed entirely.
// vite.config.js (after upgrade)
import tailwindcss from '@tailwindcss/vite';
export default {
plugins: [tailwindcss()],
};
The compatibility escape hatch
If the automated migration is too disruptive, v4 provides a compatibility layer. The @config directive loads a v3-style JavaScript config from the CSS file. This allows a project to adopt v4 without migrating the configuration immediately.
@import "tailwindcss";
@config "./tailwind.config.js";
The theme values from the JavaScript config are available, but the project does not benefit from the CSS-first model. The recommended path is to start with @config, gradually move values into @theme, and remove the JavaScript file when the migration is complete.
b. What the tool changes
The tool’s changes fall into three categories: CSS files, configuration, and templates. Each category has its own set of transformations.
CSS file changes
The @tailwind directives are replaced by a single @import. The @layer utilities blocks are converted to @utility definitions. The @layer components blocks are left in place but may need manual adjustment because they no longer interact with Tailwind’s variant system.
/* Before (v3) */
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer utilities {
.tab-4 { tab-size: 4; }
}
/* After (v4) */
@import "tailwindcss";
@utility tab-4 {
tab-size: 4;
}
The @apply statements inside custom CSS are updated to use the new utility names. If a project used @apply shadow-sm, it becomes @apply shadow-xs.
Configuration changes
The tailwind.config.js theme extensions become @theme entries. Each theme key maps to a CSS variable namespace. Colors become --color-*, spacing becomes --spacing-*, fonts become --font-*, and so on.
// Before (v3)
module.exports = {
theme: {
extend: {
colors: { brand: '#3b82f6' },
spacing: { '128': '32rem' },
},
},
};
/* After (v4) */
@theme {
--color-brand: #3b82f6;
--spacing-128: 32rem;
}
Dark mode configuration changes. The darkMode: 'class' option becomes a @custom-variant directive. The default dark variant now follows prefers-color-scheme, so a class-based toggle requires an explicit override.
/* After (v4) */
@custom-variant dark (&:where(.dark, .dark *));
Plugin configurations become @plugin directives. The typography plugin, for example, is loaded via CSS instead of JavaScript.
@plugin "@tailwindcss/typography";
Template changes
The tool scans all template files and replaces renamed utilities. It also canonicalizes arbitrary values to named values where possible. blur-[4px] becomes blur-xs, and h-[1lh] becomes h-lh.
The variant order is normalized. Stacked variants now apply left to right instead of right to left. The tool reverses the order of order-sensitive stacked variants.
<!-- Before (v3) -->
<div class="group-hover:focus:bg-blue-500">
<!-- After (v4) -->
<div class="focus:group-hover:bg-blue-500">
The ! important modifier moves from the front of the class to the end. !flex becomes flex!. The old syntax still works but is deprecated.
c. What the tool cannot do
The upgrade tool handles mechanical transformations. It cannot understand the intent behind complex configurations or custom code. Several categories of changes require manual migration.
Complex plugin configurations
The typography plugin’s configuration options cannot be automatically migrated. A project that customized prose classes through the plugin options must rewrite those customizations as CSS rules or as @utility definitions. The same applies to any plugin with a configuration object.
Custom variant functions
Variants registered via the JavaScript plugin API using addVariant() cannot be automatically converted. The tool attempts to migrate simple cases, but complex variant functions must be rewritten as @custom-variant directives.
// v3: addVariant('hocus', ['&:hover', '&:focus'])
// v4: @custom-variant hocus (&:hover, &:focus);
Dynamic theme values
If the tailwind.config.js computed theme values at build time using JavaScript logic, those values cannot be migrated to CSS. The CSS-first model does not execute JavaScript. The values must be resolved to static CSS variables or the computation must move elsewhere.
Content path configuration
The content array is removed in v4. Automatic content detection scans the project based on .gitignore rules. If the project excluded files that should be scanned, or included files that should be excluded, the @source directive must be used manually.
@import "tailwindcss";
@source "../packages/ui/src";
Safelist
The safelist option has no direct equivalent. Classes that must always be generated can be added to a @source inline(...) directive, but the syntax is different and must be written manually.
The @layer components behavior
Custom CSS in @layer components no longer works with Tailwind’s variant system. A class defined in @layer components cannot be used with hover: or lg:. If the project relies on this behavior, the classes must be converted to @utility definitions.
Complete Example Session
/* ============================================
PART 1: BEFORE MIGRATION (v3)
============================================ */
/* tailwind.config.js */
module.exports = {
darkMode: 'class',
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
colors: {
brand: {
DEFAULT: '#3b82f6',
50: '#eff6ff',
500: '#3b82f6',
900: '#1e3a8a',
},
},
fontFamily: { display: ['Inter', 'sans-serif'] },
},
},
plugins: [require('@tailwindcss/typography')],
};
/* app.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer utilities {
.tab-4 { tab-size: 4; }
}
/* ============================================
PART 2: RUN THE UPGRADE
============================================ */
// git checkout -b upgrade-tailwind-v4
// npx @tailwindcss/upgrade
// git diff
/* ============================================
PART 3: AFTER MIGRATION (v4 CSS)
============================================ */
/* app.css */
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
@plugin "@tailwindcss/typography";
@theme {
--color-brand: #3b82f6;
--color-brand-50: #eff6ff;
--color-brand-500: #3b82f6;
--color-brand-900: #1e3a8a;
--font-display: "Inter", sans-serif;
}
@utility tab-4 {
tab-size: 4;
}
/* tailwind.config.js is deleted. */
/* ============================================
PART 4: RENAMED UTILITIES IN TEMPLATES
============================================ */
/* Before */
<input class="shadow-sm blur-sm rounded-sm ring ring-blue-500" />
<button class="outline-none focus:outline-none">Click</button>
/* After (tool-applied) */
<input class="shadow-xs blur-xs rounded-xs ring-3 ring-blue-500" />
<button class="outline-hidden focus:outline-hidden">Click</button>
/* ============================================
PART 5: THE DARK MODE MIGRATION
============================================ */
/* v3: darkMode: 'class' in config */
/* v4: @custom-variant dark (&:where(.dark, .dark *)); */
/* The variant is declared in CSS, not JavaScript. */
/* The usage in templates is unchanged: <div class="dark:bg-gray-900"> */
/* ============================================
PART 6: POSTCSS CONFIGURATION
============================================ */
/* Before */
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
/* After */
module.exports = {
plugins: {
'@tailwindcss/postcss': {},
},
};
/* autoprefixer and postcss-import are removed. */
/* ============================================
PART 7: MANUAL WORK — PLUGIN CONFIG
============================================ */
/* v3 typography configuration cannot be auto-migrated. */
/* Before (tailwind.config.js) */
plugins: [
require('@tailwindcss/typography')({
className: 'wysiwyg',
}),
],
/* After (v4, manual) — the plugin is loaded without options. */
@plugin "@tailwindcss/typography";
/* Custom prose classes must be defined manually. */
@utility wysiwyg {
/* Custom styles */
}
/* ============================================
PART 8: MANUAL WORK — SAFELIST
============================================ */
/* v3 */
safelist: ['bg-red-500', 'text-white'],
/* v4 — no direct equivalent. */
/* Option: generate the classes via a source file. */
/* Option: use @source inline(...) if supported. */
/* ============================================
PART 9: VERIFICATION CHECKLIST
============================================ */
/*
[ ] All @tailwind directives replaced with @import "tailwindcss"
[ ] tailwind.config.js theme values present in @theme
[ ] Custom utilities converted to @utility
[ ] Dark mode variant declared with @custom-variant
[ ] Renamed utilities replaced in templates
[ ] Border colors explicitly set (currentColor default)
[ ] Ring utilities updated to ring-3 where 3px was intended
[ ] Plugin configurations migrated or manually rewritten
[ ] PostCSS config updated to @tailwindcss/postcss
[ ] Build succeeds with no unknown utility warnings
*/
/* ============================================
PART 10: THE COMPATIBILITY PATH
============================================ */
/* If full migration is not immediately feasible: */
@import "tailwindcss";
@config "./tailwind.config.js";
/* The v3 config works, but the project does not gain */
/* the benefits of CSS-first configuration. */
/* Migrate incrementally: move theme values to @theme, */
/* remove them from the JS config, then delete the file. */
The ten parts progressed from the v3 baseline through the upgrade command, the migrated CSS, utility renames, dark mode, PostCSS, the manual work for plugins and safelist, verification, and the compatibility path. The same project ran through every part, showing what the tool does and where manual effort is required.
Quick Reference
Upgrade Tool Scope
| Category | Automated | Manual |
|---|---|---|
@tailwind → @import | Yes | — |
Theme → @theme | Yes (simple) | Complex values |
| Utility renames | Yes | — |
| Dark mode variant | Yes | — |
| Plugin loading | Yes | Plugin configs |
| Custom variants | Partial | Complex functions |
| Safelist | No | Manual |
| Content paths | Auto-detection | @source overrides |
Renamed Utilities
| v3 | v4 | Reason |
|---|---|---|
shadow-sm | shadow-xs | Scale consistency |
shadow | shadow-sm | Scale consistency |
rounded-sm | rounded-xs | Scale consistency |
blur-sm | blur-xs | Scale consistency |
ring (3px) | ring-3 | Explicit width |
outline-none | outline-hidden | Semantic clarity |
Default Changes
| Property | v3 Default | v4 Default |
|---|---|---|
| Border color | gray-200 | currentColor |
| Ring width | 3px | 1px |
| Ring color | blue-500 | currentColor |
| Color format | HSL | OKLCH |
| Placeholder | gray-400 | 50% text opacity |
Pipeline Changes
| v3 | v4 |
|---|---|
tailwindcss PostCSS plugin | @tailwindcss/postcss |
autoprefixer required | Built-in |
postcss-import required | Built-in |
tailwind.config.js auto-detected | Not auto-detected; use @config or migrate |
Best Practices
✅ Do This:
# Run on a clean branch.
git checkout -b upgrade-tailwind-v4 # ✅
# Review every diff.
git diff # ✅
# Update Node.js to 20+ before running.
node --version # ✅
# Use @config for gradual migration.
@config "./tailwind.config.js"; # ✅
# Convert @layer utilities to @utility.
@utility tab-4 { tab-size: 4; } # ✅
# Declare dark variant explicitly.
@custom-variant dark (&:where(.dark, .dark *)); # ✅
# Verify the build after upgrade.
npm run build # ✅
❌ Don’t Do This:
# Don't run on uncommitted changes.
npx @tailwindcss/upgrade # ❌ No rollback possible
# Don't assume the tool handles everything.
# Complex plugin configs require manual work. # ❌
# Don't leave tailwind.config.js without @config.
# It is silently ignored in v4. # ❌
# Don't use @layer utilities for variant-aware classes.
@layer utilities { .foo { ... } } # ❌ Use @utility
# Don't skip the verification checklist.
# Renamed utilities break styles silently. # ❌
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Config silently ignored | tailwind.config.js not auto-detected | Migrate to @theme or add @config |
| Utilities not renamed | Tool missed edge cases | Manual grep for renamed classes |
| Border colors wrong | Default changed to currentColor | Add explicit border colors |
| Ring width changed | Default changed from 3px to 1px | Use ring-3 where 3px intended |
| Plugin config lost | Complex configs not auto-migrated | Rewrite as CSS or @utility |
| Dark mode broken | darkMode: 'class' no longer applies | Add @custom-variant |
| Custom variants missing | addVariant() not auto-migrated | Rewrite as @custom-variant |
| Safelist classes absent | No safelist in v4 | Use @source or generate explicitly |
Real-World Examples
1. Basic Upgrade Command
npx @tailwindcss/upgrade
2. The @import Replacement
/* v4 */
@import "tailwindcss";
3. The @theme Block
@theme {
--color-brand: #3b82f6;
--font-display: "Inter", sans-serif;
}
4. The @utility Directive
@utility tab-4 {
tab-size: 4;
}
5. The @custom-variant for Dark Mode
@custom-variant dark (&:where(.dark, .dark *));
6. The @plugin Directive
@plugin "@tailwindcss/typography";
7. Renamed Utility Replacement
<!-- Before -->
<div class="shadow-sm ring outline-none">
<!-- After -->
<div class="shadow-xs ring-3 outline-hidden">
8. The Compatibility Escape
@import "tailwindcss";
@config "./tailwind.config.js";
9. Explicit Border Color
<!-- v4 requires explicit border color -->
<div class="border border-gray-200">
10. PostCSS Config Simplification
module.exports = {
plugins: { '@tailwindcss/postcss': {} },
};
Visual
The Upgrade Flow
┌────────────────────────────────────────────────────────────┐
│ THE UPGRADE PROCESS │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ v3 Project │ │
│ │ tailwind.config.js │ │
│ │ @tailwind base/components/utilities │ │
│ │ @layer utilities { ... } │ │
│ └──────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌──────────────────────────────────────────────────┐ │
│ │ npx @tailwindcss/upgrade │ │
│ │ - Updates dependencies │ │
│ │ - Migrates CSS files │ │
│ │ - Converts config to @theme │ │
│ │ - Renames utilities in templates │ │
│ │ - Updates PostCSS config │ │
│ └──────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌──────────────────────────────────────────────────┐ │
│ │ v4 Project (automated) │ │
│ │ @import "tailwindcss" │ │
│ │ @theme { ... } │ │
│ │ @utility { ... } │ │
│ │ @custom-variant dark { ... } │ │
│ └──────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Manual work required │ │
│ │ - Plugin configs │ │
│ │ - Custom variant functions │ │
│ │ - Safelist │ │
│ │ - Dynamic theme values │ │
│ └──────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Verification │ │
│ │ - Build succeeds │ │
│ │ - Visual regression check │ │
│ │ - Renamed utilities applied │ │
│ └──────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────┘
Configuration Migration
┌────────────────────────────────────────────────────────────┐
│ JS CONFIG → CSS @theme │
│ │
│ v3 (tailwind.config.js) │
│ ┌──────────────────────────────────────────────────┐ │
│ │ theme: { │ │
│ │ extend: { │ │
│ │ colors: { brand: '#3b82f6' }, │ │
│ │ spacing: { '128': '32rem' }, │ │
│ │ fontFamily: { display: ['Inter'] }, │ │
│ │ }, │ │
│ │ }, │ │
│ └──────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ v4 (app.css) │
│ ┌──────────────────────────────────────────────────┐ │
│ │ @theme { │ │
│ │ --color-brand: #3b82f6; │ │
│ │ --spacing-128: 32rem; │ │
│ │ --font-display: "Inter", sans-serif; │ │
│ │ } │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ Namespace mapping: │
│ colors → --color-* │
│ spacing → --spacing-* │
│ fontFamily → --font-* │
│ borderRadius → --radius-* │
│ │
└────────────────────────────────────────────────────────────┘
The Compatibility Path
┌────────────────────────────────────────────────────────────┐
│ GRADUAL MIGRATION WITH @config │
│ │
│ STEP 1: Adopt v4 with compatibility layer │
│ ┌──────────────────────────────────────────────────┐ │
│ │ @import "tailwindcss"; │ │
│ │ @config "./tailwind.config.js"; │ │
│ │ (v3 config works, no CSS-first benefits) │ │
│ └──────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ STEP 2: Move values to @theme incrementally │
│ ┌──────────────────────────────────────────────────┐ │
│ │ @import "tailwindcss"; │ │
│ │ @config "./tailwind.config.js"; │ │
│ │ @theme { │ │
│ │ --color-brand: #3b82f6; │ │
│ │ } │ │
│ │ (Brand moved; rest still in JS config) │ │
│ └──────────────────────────────────────────────────┘ │
│ │ │
│ v │
│ STEP 3: Remove the JS config entirely │
│ ┌──────────────────────────────────────────────────┐ │
│ │ @import "tailwindcss"; │ │
│ │ @theme { │ │
│ │ --color-brand: #3b82f6; │ │
│ │ --font-display: "Inter", sans-serif; │ │
│ │ } │ │
│ │ (Full CSS-first configuration) │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ @config is a bridge, not a destination. │
│ │
└────────────────────────────────────────────────────────────┘
Utility Renames
┌────────────────────────────────────────────────────────────┐
│ RENAMED UTILITIES (AUTOMATED) │
│ │
│ v3 Class → v4 Class │
│ ───────────────────────────────────── │
│ shadow-sm → shadow-xs │
│ shadow → shadow-sm │
│ rounded-sm → rounded-xs │
│ rounded → rounded-sm │
│ blur-sm → blur-xs │
│ blur → blur-sm │
│ ring (3px) → ring-3 │
│ outline-none → outline-hidden │
│ │
│ The tool replaces these across all template files. │
│ Verify with grep after the upgrade. │
│ │
└────────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
@tailwindcss/upgrade | Automated migration tool for v3 to v4 |
| Requirement | Node.js 20+, clean git branch |
| Configuration | tailwind.config.js → @theme in CSS |
| Directives | @tailwind → @import "tailwindcss" |
| Custom utilities | @layer utilities → @utility |
| Custom variants | addVariant() → @custom-variant |
| Plugins | require() → @plugin directive |
| PostCSS | tailwindcss → @tailwindcss/postcss |
| Autoprefixer | Removed; built into v4 |
| Compatibility | @config loads v3 JS config |
| Manual work | Plugin configs, custom variants, safelist |
| Verification | git diff and build test |
Key takeaways:
- The upgrade is structural, not cosmetic. v4 changes the configuration model, the directives, the utility taxonomy, the color system, and the plugin API. The tool automates the mechanical parts, but understanding the scope is necessary for verification.
- Run on a clean branch. The tool modifies files in place with no dry-run mode. Version control is the only rollback mechanism. Review every diff before committing.
- Configuration moves to CSS. The
tailwind.config.jsfile is no longer auto-detected. Theme values become@themeentries, custom utilities become@utility, and custom variants become@custom-variant. - The tool handles simple cases, not complex ones. Plugin configurations, custom variant functions, dynamic theme values, and safelist entries require manual migration. The tool’s output is a starting point, not a finished upgrade.
- Utility renames are the most visible change.
shadow-smbecomesshadow-xs,ringbecomesring-3,outline-nonebecomesoutline-hidden. These are replaced automatically, but verification is necessary. - Defaults changed. Borders default to
currentColor, rings default to 1px andcurrentColor, and the color palette uses OKLCH. Explicit colors are required where the old defaults were relied upon. @configis a bridge. A project that cannot migrate immediately can load its v3 JavaScript config with@config. The recommended path is incremental migration: move values to@themeone namespace at a time, then delete the JavaScript file.- Verify the build and the visuals. A successful build does not guarantee correct styling. Renamed utilities that were missed, border colors that default to
currentColor, and ring widths that changed can all break layouts silently.
Remember: The @tailwindcss/upgrade tool automates the bulk of the v3 to v4 migration: it converts configuration to CSS, renames utilities, updates dependencies, and simplifies the PostCSS pipeline. It cannot understand intent. Complex plugin configurations, custom variant functions, and dynamic theme values require manual work. Run the tool on a clean branch, review every change, and treat the output as a starting point rather than a finished migration. The v4 model is CSS-first: configuration lives in @theme, custom utilities live in @utility, and custom variants live in @custom-variant. The JavaScript configuration file that anchored every project since v1 is no longer auto-detected, and a project that leaves it in place without @config will build with default Tailwind, silently ignoring every customization.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!