DEV Community

Vildanden
Vildanden

Posted on

Scoped Cursor Rules for Next.js App Router: Conventions, Server Actions, and Security

A Cursor rule that applies to every file is easy to write and surprisingly easy to ignore. In a Next.js App Router project, a convention for app/ is useful while editing route code, a server-action reminder belongs near mutations, and a security checklist should be visible at server boundaries. Those are different contexts, so they should not be one oversized instruction file.

This tutorial builds three small .mdc rules with different scopes. The goal is not to make an agent autonomous. The goal is to put the right reminder beside the code where a mistake would be expensive.

If you want the background model first, see A Minimal AGENTS.md and Cursor Rules Setup for Next.js App Router. This article takes the narrower, hands-on path: designing and installing the Cursor rules themselves.

What we are building

Assume a conventional App Router repository:

app/
  dashboard/page.tsx
  settings/actions.ts
  api/reports/route.ts
components/
lib/
.cursor/
  rules/
Enter fullscreen mode Exit fullscreen mode

We will add:

  1. app-conventions.mdc for route and component conventions.
  2. server-actions.mdc for mutations and server-side data access.
  3. security-boundaries.mdc for authentication, authorization, validation, and secret handling.

The first two rules are scoped to relevant paths. The security rule is deliberately broader, because a secret or authorization mistake can happen in a route, a library, or a component boundary.

1. Create the rules directory

From the project root:

mkdir -p .cursor/rules
Enter fullscreen mode Exit fullscreen mode

If the project already has .cursor/rules/, inspect the existing files before adding new ones. Keep one responsibility per rule. A rule should be small enough that a teammate can review it in one sitting.

2. Add the App Router conventions rule

Create .cursor/rules/app-conventions.mdc:

---
description: "Next.js App Router and React conventions"
globs: "app/**/*.{ts,tsx},components/**/*.{ts,tsx}"
alwaysApply: false
---

# App Router conventions

- Keep route UI, loading states, and error boundaries close to their route under `app/`.
- Prefer Server Components by default.
- Add `"use client"` only for hooks, browser APIs, or interactive event handlers.
- Keep Client Components small and pass serializable props from the server.
- Reuse the repository's existing components and data-access patterns before creating new ones.
- Use the project's existing path layout; if it uses `src/`, update this rule's globs.
- Prefer `next/link` and `next/image` for internal links and images.
- Preserve the project's loading, empty, and error states when changing a route.
Enter fullscreen mode Exit fullscreen mode

There is one intentional detail here: this rule does not say “always use Server Components.” It says to start there and name the exceptions. A settings form or a browser-only widget may need the client. A scoped rule should guide judgment, not prohibit valid architecture.

The globs line also makes the rule easier to reason about. Editing components/ should show component conventions; editing a documentation file should not. If your application lives at src/app, use patterns such as src/app/**/*.{ts,tsx} instead.

Note: Keep the frontmatter keys exactly as your Cursor version expects. The description, globs, and alwaysApply fields are the useful minimum for a scoped project rule.

3. Add the server actions rule

Create .cursor/rules/server-actions.mdc:

---
description: Server Actions, route handlers, and server-side data access
globs: "app/**/*.{ts,tsx},lib/**/*.{ts,tsx}"
alwaysApply: false
---

# Server-side mutations and data

- Treat every Server Action and Route Handler as a public server boundary.
- Validate form data, JSON, params, and search params before using them.
- Check authentication and authorization on the server; client checks are only UX.
- Keep database and secret-bearing calls in server-only modules.
- Return a safe result shape; do not send stack traces or private fields to the client.
- Revalidate the specific path or tag affected by a successful write.
- Make mutations idempotent where retries are possible.
- Add focused tests for authorization and invalid input when changing a mutation.
Enter fullscreen mode Exit fullscreen mode

The key phrase is public server boundary. A Server Action is called from a UI, but it is still a server entry point. Anyone who can reach the application may attempt to invoke the endpoint, so hiding the button is not an authorization mechanism.

For example, a mutation should validate both its input and the current user:

"use server";

import { revalidatePath } from "next/cache";
import { z } from "zod";
import { requireUser } from "@/lib/auth";import { updateProfile } from "@/lib/data";const profileSchema = z.object({
  displayName: z.string().trim().min(1).max(80),
});

export async function saveProfile(formData: FormData) {
  const user = await requireUser();
  const input = profileSchema.parse({
    displayName: formData.get("displayName"),
  });

  await updateProfile({ userId: user.id, ...input });
  revalidatePath("/settings");
  return { ok: true } as const;
}
Enter fullscreen mode Exit fullscreen mode

The example is intentionally boring. It establishes the boundary, narrows untrusted data, uses the authenticated user rather than a user ID supplied by the browser, and revalidates only the affected route.

Do not copy this example blindly. Match the repository's existing schema, auth, data-access, and error-handling libraries. The rule is there to make those decisions visible while the file is open.

4. Add the security boundaries rule

Create .cursor/rules/security-boundaries.mdc:

---
description: Security checks for Next.js server and client boundaries
globs: "**/*.{ts,tsx,js,jsx}"
alwaysApply: true
---

# Security boundaries

- Never place secrets, private tokens, or privileged SDK calls in Client Components.
- Use `NEXT_PUBLIC_*` only for values that are safe to expose in the browser.
- Enforce authorization on the server for every protected read and mutation.
- Treat request data, cookies, headers, URL params, and third-party responses as untrusted.
- Avoid rendering user-provided HTML; if HTML is required, use the project's reviewed sanitizer.
- Do not log passwords, tokens, session cookies, or sensitive personal data.
- Return generic client-facing errors and keep diagnostic details in protected server logs.
- Never commit `.env` files, credentials, or generated secret-bearing output.
Enter fullscreen mode Exit fullscreen mode

This rule is alwaysApply: true because security concerns cross directory boundaries. Its job is to catch the dangerous category error: trusting a value because it came from a UI, a cookie, a hidden field, or a third-party API.

It is still not a security review. Keep code review, dependency updates, CI checks, and your application's threat model. A rule can remind an agent to check authorization; it cannot prove that the authorization policy is correct.

5. Install the free Vildanden sample instead

If you prefer ready-to-copy files, download the free Vildanden Next.js + React sample:

https://vildanden.gumroad.com/l/xphax

Then:

  1. Download and extract the sample outside your application first.
  2. Copy or merge AGENTS.md and CLAUDE.md into the repository root; preserve useful project-specific guidance.
  3. Copy the .cursor/rules/*.mdc files into your project's .cursor/rules/ directory.
  4. Change every glob that does not match your layout, especially src/app, monorepo package paths, or custom component directories.
  5. Reopen the repository in Cursor so the project rules are loaded.
  6. Make a small test edit in app/, a server mutation, and a security-sensitive file. Confirm the relevant rules appear in the editor context.
  7. Run the repository's normal typecheck, lint, and focused tests.

The files are configuration, not a runtime package: there is nothing to add to package.json, no production dependency, and no database migration.

A quick review checklist

Before committing your rules, check:

  • Does every scoped rule match the directories your project actually uses?
  • Is any rule repeating a longer instruction file word for word?
  • Are server mutations told to validate input and authorize the current user?
  • Are secrets and privileged calls kept out of Client Components?
  • Does the guidance preserve local conventions instead of forcing a new architecture?
  • Can a teammate understand the rule without opening another five files?

If a rule keeps producing irrelevant suggestions, narrow its glob or split it by responsibility. If an important reminder is missing at a boundary, add one concrete line rather than another page of principles.

Want more stacks and rules?

The free sample covers Next.js + React. The optional Vildanden pack adds more stacks, additional rule coverage, and more prompt templates:

https://vildanden.gumroad.com/l/daody

Start with the free sample, adapt the globs to your repository, and keep only the guidance that reflects how your team actually ships.

Disclosure: This tutorial was created for Vildanden and links to Vildanden downloads. The examples are educational defaults, not a substitute for your project's review and security practices.

Top comments (1)

Collapse
 
citedy profile image
Dmitry Sergeev

We need to produce a comment per developer style: short, 1-2 sentences, start with lowercase, maybe ask a question about video. No quotes, no markdown. Must not be promotional. Must avoid double hyphen, no em dash. Ensure no URLs. Should reference video content: Scoped Cursor Rules for Next.js App Router: Conventions, Server Actions, and Security. Could ask about how cursor rules interact with server actions. Must be short. We need to output only comment text. No JSON. Ensure no punctuation rules