DEV Community

Cover image for I built two Next.js 15 + Tailwind v4 templates with zero extra dependencies — here's what I learned
Sanmukapriya
Sanmukapriya

Posted on

I built two Next.js 15 + Tailwind v4 templates with zero extra dependencies — here's what I learned

Earlier this month I shipped two premium templates — a SaaS landing page and a developer portfolio. Not a startup, not a SaaS, just templates. This post is about the two constraints I built them under, why they made the code better, and a few things I learned launching as a solo dev with zero audience.

Constraint 1: zero dependencies beyond next, react, and tailwind

Open the package.json of most templates and you'll find 20+ packages: icon libraries, animation libraries, carousel plugins, UI kits, utility libraries. Every one of them is a version conflict waiting to happen for the buyer, and most are replaceable with a few lines of code in 2026.

What I used instead:

  • Icons → inline SVG components. An icon component is ~10 lines. You need maybe 15 icons for a landing page.
  • Animations → plain CSS. Scroll-blur navbars, gradient glows, an animated "typing" terminal — all doable with keyframes and transitions. No framer-motion.
  • The dashboard mockup in the hero → pure CSS. Divs, borders, gradients. It looks like a product screenshot but it's ~80 lines of JSX and weighs nothing.

Result: both templates land at ~100KB first-load JS, npm install takes seconds, and there is nothing to break when Next.js 16 arrives.

Constraint 2: every piece of content in ONE typed config file

The thing I hated most about templates I've used: content is smeared across 30 components. Changing a headline means hunting through JSX.

So both templates keep all content in a single file — lib/content.ts for the landing page, site.config.ts for the portfolio. Headlines, nav, pricing tiers, testimonials, project lists, even the lines that animate in the fake terminal. Components are pure renderers of that config's TypeScript type.

Two things surprised me here:

  1. TypeScript becomes your content linter. Forget an alt text, malform a link, give a pricing tier three features when the type expects a non-empty array — the build fails. Content mistakes surface at compile time.
  2. It forces better component design. When a component can only receive data shaped by the config type, you stop leaking one-off props and hardcoded strings everywhere. Every section component got simpler.

If you're building anything content-heavy — a portfolio, docs, a marketing site — I'd genuinely recommend this structure even if you never sell it.

Tailwind v4 notes (the migration was smaller than feared)

Both templates use Tailwind CSS v4. The headline change: there's no tailwind.config.js anymore — theme tokens live in CSS via @theme:

@import "tailwindcss";

@theme {
  --color-accent: oklch(0.72 0.15 260);
  --font-sans: "Inter", sans-serif;
}
Enter fullscreen mode Exit fullscreen mode

Custom colors become CSS variables you can also read at runtime, @apply still works where you need it, and the content-scanning config is gone (v4 finds your classes itself). For a fresh project there's honestly less to learn than v3.

Launching with zero audience: early notes

I have no Twitter following, no newsletter, no LinkedIn presence. Things I've done in week one:

  • Live demos on Vercel (free tier) — nothing converts interest like a clickable demo
  • Template directories — submitted to Built At Lightspeed and Statichunt; these listings also feed AI-assistant recommendations, which is quietly becoming a real discovery channel
  • Reddit — learned the hard way that a 0-day-old account posting links gets auto-filtered. Build comment karma first.

No sales yet as I write this — I'll do a follow-up post when there's real data, including what worked and what was a waste of time.

The templates

If you want to see the constraints above in practice, both demos are live:

They're paid templates (links on the demo pages), but the ideas in this post — zero-dep icons, single-config content, @theme — are free to steal for your own projects.

Questions about the structure or the Tailwind v4 setup? Ask below — I'll answer everything.

Top comments (3)

Collapse
 
jig_saw_4a65f018b90732812 profile image
Jig Saw

Nice work keeping dependencies minimal. One area where I've been able to cut plugins is image handling. Instead of pulling in sharp or a CDN-specific library, I use Cloudinary's URL-based transformations. It means I can serve optimized images in Next.js without any extra packages, and the CDN is built in. It's a nice complement to the zero-dependency mindset.

Collapse
 
publiflow profile image
PubliFlow

Dropping extra dependencies in Next.js 15 and Tailwind v4 is a great way to keep the bundle size minimal, but I am curious how you handled state management without external libraries. In my experience with similar zero-dependency setups, relying purely on React context and useReducer can lead to unnecessary re-renders if the context tree gets too deep. Did you find yourself splitting contexts frequently to isolate component updates, or did you stick to a single global provider? Also, migrating to Tailwind v4's new CSS-first configuration must have required some interesting adjustments to your custom utility classes.

Collapse
 
publiflow profile image
PubliFlow

Building with zero extra dependencies in Tailwind v4 is a great exercise in understanding the core utility classes without relying on plugins. I found that when migrating to v4, the new CSS-first configuration approach actually makes it easier to drop heavy utility plugins since you can just write custom CSS variables directly in your stylesheet. Did you run into any edge cases with the new Oklch color space handling when trying to keep the bundle completely dependency-free?