DEV Community

Cover image for How I went from getting tired of explaining the same things to AI, to developing a cutting edge solution, to accidentally creating a brand
Diogo Abreu
Diogo Abreu

Posted on

How I went from getting tired of explaining the same things to AI, to developing a cutting edge solution, to accidentally creating a brand

There’s a moment every developer hits when “AI-assisted coding” starts feeling less like acceleration and more like friction.

For me, that moment came somewhere between deleting yet another useEffect-based data fetch and watching Cursor confidently generate a tailwind.config.js file in a project that absolutely did not need one.

That loop kept repeating:

  • Wrong patterns
  • Outdated APIs
  • Defaults that no longer reflect how modern apps are built

And the more cutting-edge the stack became—Next.js 16, React 19, Tailwind v4—the worse it got.

So I stopped fixing the symptoms and built my own rules pack instead.
Afterwards, I wanted to have some place that I could centralize it and future digital products and tools.

That place became Saastenance—and this post is both a technical deep dive and the story of how a small dev tool quietly turned into a full digital product and part of a brand.


The Real Problem: AI Is Only As Good As Its Defaults

Tools like Cursor and Claude Code don’t “understand” your stack—they pattern match based on training data.

And most of that data is already outdated.

So unless you explicitly constrain them, they will:

  • Reintroduce deprecated patterns
  • Ignore new framework primitives
  • Drift away from your architecture over time

What I needed wasn’t better prompts.

I needed persistent, enforceable rules.


Enter: The AI Rules Pack

The AI Rules Pack is a structured set of rules (in .mdc format) that:

  • Defines how your AI should think
  • Locks in modern best practices
  • Prevents regression into outdated patterns

It works with Cursor, Claude Code, and OpenAI Codex. It installs via a CLI where you choose your stack preferences.

But the interesting part—the reason it exists—comes from how Next.js 16 broke a lot of assumptions.

Let’s walk through that.


Breaking Changes in Next.js 16 (That AI Keeps Getting Wrong)

1. Data Fetching: useEffect Is No Longer the Default

❌ Before (what AI still generates)

'use client'

import { useEffect, useState } from 'react'

export default function Page() {
  const [data, setData] = useState(null)

  useEffect(() => {
    fetch('/api/data')
      .then(res => res.json())
      .then(setData)
  }, [])

  return <div>{JSON.stringify(data)}</div>
}
Enter fullscreen mode Exit fullscreen mode

✅ After (Next.js 16 pattern)

export default async function Page() {
  const data = await fetch('https://api.example.com/data', {
    cache: 'no-store'
  }).then(res => res.json())

  return <div>{JSON.stringify(data)}</div>
}
Enter fullscreen mode Exit fullscreen mode

Why this matters

  • Server Components are the default
  • Fetching happens on the server
  • No client waterfall, no loading flicker

Yet AI still defaults to client-side fetching unless told otherwise.


2. Server Actions Replace Client Mutation Logic

❌ Before

'use client'

async function handleSubmit(formData) {
  await fetch('/api/form', {
    method: 'POST',
    body: JSON.stringify(formData)
  })
}
Enter fullscreen mode Exit fullscreen mode

✅ After

export async function submit(formData: FormData) {
  'use server'

  // direct DB call or mutation
}
Enter fullscreen mode Exit fullscreen mode
<form action={submit}>
  <button type="submit">Submit</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Why this matters

  • No API route needed
  • No client fetch boilerplate
  • Stronger co-location of logic

AI often mixes both patterns—which creates unnecessary complexity.


3. middleware.ts Is No Longer Your Auth Layer

This one shows up constantly.

❌ Before

// middleware.ts
import { NextResponse } from 'next/server'

export function middleware(req) {
  // auth logic
}
Enter fullscreen mode Exit fullscreen mode

✅ After

  • Use route handlers, server actions, or framework-native auth solutions
  • Middleware is now edge-specific and limited

Why this matters

AI overuses middleware because it used to be a catch-all solution.

In modern apps, it's usually the wrong tool.


4. Tailwind v4: No tailwind.config.js

❌ Before

module.exports = {
  theme: {
    extend: {}
  }
}
Enter fullscreen mode Exit fullscreen mode

✅ After

  • Zero-config by default
  • CSS-first configuration
@theme {
  --color-primary: blue;
}
Enter fullscreen mode Exit fullscreen mode

Why this matters

AI still scaffolds Tailwind like it's 2021.

That leads to unnecessary files and wrong mental models.


5. Forms: useFormState Is Not the Move

❌ Before

const [state, formAction] = useFormState(action, initialState)
Enter fullscreen mode Exit fullscreen mode

✅ After

  • Use native <form action={serverAction}>
  • Or lightweight client validation where needed

Why this matters

React 19 + Server Actions changed the ergonomics completely.

Yet AI keeps reaching for older abstractions.


6. Routing + Layout Assumptions

AI still:

  • Overuses client components
  • Misplaces logic in layouts
  • Avoids async components

✅ Modern expectation

  • Layouts are server-first
  • Components are async by default
  • Client components are opt-in

The Pattern Behind the Problems

None of these issues are “bugs.”

They’re default mismatches.

AI is trained on:

  • Older Next.js versions
  • Mixed patterns
  • Transitional APIs

So unless you enforce constraints, it will:

  • Blend paradigms
  • Reintroduce deprecated logic
  • Slow your team down

The Solution: Encode Your Standards

That’s what the AI Rules Pack does.

Instead of correcting AI every time, you:

  • Define rules once
  • Apply them automatically
  • Keep outputs consistent across projects

Example Rule (Conceptually)

- NEVER use useEffect for data fetching
- ALWAYS prefer server components
- USE server actions for mutations
- DO NOT create tailwind.config.js
Enter fullscreen mode Exit fullscreen mode

Now scale that across:

  • Architecture decisions
  • Naming conventions
  • Library choices
  • Auth/data patterns

That’s where this becomes powerful.


The nextjs-core.mdc (Free)

Here’s the free core rules file for Next.js:

// nextjs-core.mdc
---
description: Next.js 16 Cache Components — "use cache" directive, cacheLife profiles, cacheTag, updateTag, refresh, and the new caching mental model
globs: "**/*.ts,**/*.tsx"
alwaysApply: true
---

## Next.js 16 — Cache Components

### The New Mental Model

In Next.js 16 with `cacheComponents: true`, **everything is dynamic by default**. Caching is entirely opt-in. This is the opposite of Next.js 13-15 where `fetch()` was cached by default and you had to opt out.

Old model (Next.js 13-15):

- `fetch()` → cached by default
- Add `cache: 'no-store'` to opt out
- `export const revalidate = 60` for ISR
- Confusing implicit behaviour

New model (Next.js 16 Cache Components):

- Everything dynamic by default
- Add `"use cache"` to opt into caching
- `cacheLife()` sets the duration
- `cacheTag()` enables on-demand invalidation
- Explicit, predictable, composable

### Setup

(add ts code block tags here)
// next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  cacheComponents: true,

  // Optional: define custom profiles
  cacheLife: {
    products: { stale: 300, revalidate: 900, expire: 86400 },
    dashboard: { stale: 60, revalidate: 300, expire: 3600 },
    blog: { stale: 3600, revalidate: 900, expire: 86400 },
    realtime: { stale: 0, revalidate: 10, expire: 60 },
  },
};

export default nextConfig;
(close code blocks)

### The `"use cache"` Directive

Add at the top of any async function, component, page, or layout to make it cacheable.

(add ts code block tags here)
import { cacheLife, cacheTag } from "next/cache"

// Cache a data access function
export async function getProducts(category: string) {
  "use cache"
  cacheLife("hours")
  cacheTag("products", `category-${category}`)
  // arguments automatically become part of the cache key
  // getProducts("shoes") and getProducts("hats") are separate cache entries
  return db.query.products.findMany({ where: { category } })
}

// Cache a Server Component
async function FeaturedProducts() {
  "use cache"
  cacheLife("hours")
  cacheTag("products")
  const products = await db.query.products.findMany({ where: { featured: true } })
  return (
    <ul>
      {products.map(p => <ProductCard key={p.id} product={p} />)}
    </ul>
  )
}

// Cache an entire page
export default async function BlogPage() {
  "use cache"
  cacheLife("days")
  const posts = await getPosts()
  return <PostList posts={posts} />
}

// Cache a layout
export default async function MarketingLayout({ children }: { children: React.ReactNode }) {
  "use cache"
  cacheLife("max")
  const nav = await getNavLinks()
  return (
    <div>
      <Nav links={nav} />
      {children}
    </div>
  )
}
(close code blocks)
Enter fullscreen mode Exit fullscreen mode

This alone eliminates a huge percentage of bad AI output.


From Dev Tool → Product → Brand

Originally, this wasn’t meant to be a product.

It was just a personal fix.

But then:

  • I made it reusable
  • Added a CLI installer
  • Wrote documentation
  • Structured it for different stacks

And at some point, I realized:

How am I going to centralize this product and other side projects so people know what they're getting?

That’s when Saastenance was born.

Not just for this pack—but as a storefront for:

  • Developer tools
  • AI workflows
  • Opinionated systems that reflect how things are actually built today

What You Get

The AI Rules Pack includes:

  • Full rule sets for modern frontend SaaS
  • Cursor + Claude Code + OpenAI Codex compatibility
  • CLI installer (one command setup)
  • Stack customization
  • Git commit conventions for automatic commit message suggestions
  • Complementary Cursor Memories guide
  • Documentation + usage guide

It’s designed to answer one question:

“How do I make AI code like a senior developer on my team?”


Launch Offer

To celebrate the launch, I’m offering:

30% off with code: SAASTELAUNCH30 (valid through May)


Final Thought

AI isn’t replacing developers.

But developers who systemize AI will replace those who don’t.

You can keep correcting outputs…

Or you can define the rules once—and never fight the same battle again.


Get the Full Pack

👉 https://saastenance.com/products/ai-rules-pack-frontend-development


If you're building with modern frontend tools, this will save you hours—and a lot of frustration.

And if nothing else, hopefully this gave you a clearer picture of how Next.js 16 is reshaping the way we write frontend code—and why your AI might still be living in the past.

Top comments (0)