Next.js + Supabase Application
Coordinates Next.js rendering, Supabase authentication, database access, and safe public environment configuration.
Scenario
You maintain a production SaaS application built with:
- Next.js App Router;
- TypeScript;
- Supabase Auth;
- Supabase PostgreSQL;
- Row Level Security;
- server and client components;
- Vitest and Playwright.
The application contains authenticated user data and organization-scoped resources.
The repository has reached the point where isolated instructions such as:
use TypeScript
run tests
use Supabase
are no longer enough.
Agents need guidance covering architecture, security, data access, migrations, and validation together.
Repository Structure
saas-app/
├── app/
│ ├── (public)/
│ ├── (dashboard)/
│ ├── api/
│ └── layout.tsx
├── src/
│ ├── features/
│ ├── components/
│ │ └── ui/
│ ├── lib/
│ │ └── supabase/
│ │ ├── browser.ts
│ │ ├── server.ts
│ │ └── admin.ts
│ └── authorization/
├── supabase/
│ └── migrations/
├── tests/
│ ├── integration/
│ └── e2e/
├── package.json
└── AGENTS.md
AGENTS.md
# Project Instructions
## Development
- Use `pnpm`.
- Follow the existing Next.js App Router architecture.
- Keep feature-specific behavior under `src/features`.
- Reuse shared UI primitives from `src/components/ui`.
## Next.js
- Prefer Server Components unless browser state, effects, event handlers, or browser APIs require a Client Component.
- Keep `"use client"` boundaries as narrow as practical.
- Use Route Handlers for server-side HTTP endpoints when required.
- Do not expose server-only configuration or credentials to client components.
## Supabase
- Use the existing browser and server Supabase client helpers.
- Use the admin/service-role client only in trusted server-side workflows that explicitly require elevated access.
- Never expose the service-role key to browser code.
## Authorization
- Authentication does not automatically grant access to organization resources.
- Preserve existing authorization and tenant-boundary checks.
- Do not trust organization IDs or ownership claims supplied by the client without server-side verification.
## Row Level Security
- Treat RLS as part of the authorization model.
- Do not disable RLS to make a query succeed.
- Add or update policies when new user-accessible data operations require them.
- Test important allowed and denied access paths.
## Database Changes
- Make schema and policy changes through Supabase migrations.
- Do not rely on manual dashboard-only schema changes.
- Do not rewrite already-applied migrations.
- Consider existing production data before adding required constraints.
## Testing
- Add or update tests when behavior changes.
- Add regression coverage for reproducible bugs when practical.
- Use integration tests for important API/data-access behavior.
- Use Playwright for critical user workflows.
## Validation
During development, run targeted checks.
Before completing substantial changes, run:
- `pnpm lint`
- `pnpm typecheck`
- relevant tests
- `pnpm build`
For schema or RLS changes, also validate the relevant migration and authorization behavior.
What This Does
This combines several concerns into one production-oriented instruction set.
For example, implementing:
Organization settings page
may involve:
Server Component
↓
Supabase server client
↓
authenticated user
↓
organization authorization
↓
RLS-protected data
An agent should reason about the complete path rather than only making the UI render.
Another example is introducing a new table.
That change may require:
migration
+
RLS policy
+
server query
+
generated types if used
+
tests
rather than only:
CREATE TABLE ...
What This Does NOT Do
The file does not require every component to be a Server Component.
Interactive UI still needs client behavior.
It also does not prohibit service-role access.
The distinction is:
normal user operation
→ user-scoped access
trusted privileged workflow
→ elevated access when justified
The instructions also do not duplicate every Next.js or Supabase documentation page.
They capture the repository-specific decisions that agents need while changing code.
Why These Instructions Matter
Production applications fail at boundaries between technologies.
For example:
Next.js page works
Supabase query works
authentication works
can all be individually true while authorization is still incorrect.
Suppose an authenticated user sends:
{
"organizationId": "another-company"
}
and the server trusts that value without checking membership.
The feature can be technically functional while violating tenant isolation.
Another dangerous shortcut occurs when RLS blocks a query.
Switching to:
service-role client
can make the feature work while silently bypassing authorization.
That is why production instructions need to connect architecture and security rather than describe them separately.
Key Decisions
Server-first does not mean server-only
Use Server Components as the normal starting point, then introduce client boundaries where interactivity requires them.
Authentication and authorization are separate
A valid session identifies the user.
It does not prove access to every resource.
RLS is part of correctness
For user-owned or tenant-owned data, policy behavior is part of the feature.
Database changes include security
A new user-facing table may be incomplete until its RLS behavior is defined.
Validation follows blast radius
A small component change may need targeted tests.
A schema, authentication, or shared architecture change deserves broader validation.
When to Use This Pattern
Use this pattern when:
- Next.js and Supabase power a production application;
- authentication and tenant authorization matter;
- RLS protects application data;
- both server and client rendering are used;
- database migrations are committed;
- several testing levels exist.
This pattern demonstrates how a production AGENTS.md should connect framework architecture, security, persistence, and validation.