The application code contains no permission checks; access rules are centralized in the single file db/policy.authz
starter-nextjs-prisma — Next.js Starter Template
By rowstile
A document-sharing starter built on Next.js App Router and Prisma, with no permission checks in the application code. Access rules are centralized in a single policy file and compiled by rowstile into Postgres row-level security policies.
Explore the design
Compare the page layouts and mobile experience. Open any screenshot for a closer look.
Actual screenshot captured by the server browser.
All pages & views 3
Screenshots show visual appearance; interactive behavior may differ.
What stands out
A quick read of the recorded project description.
Rules are compiled by rowstile into Postgres row-level security policies, with filtering and rejection enforced by the database
Provides a one-command docker compose startup for Postgres, migrations, and the app
Rule tests live in db/tests/sharing.authz, and each test brings its own data and rolls back
The CI workflow runs the tests and comments on pull requests about who gains or loses access
Apache-2.0 licensed, free to use, modify, and distribute
Template Details
This is a starter for a document-sharing scenario: documents are shared between users and between users and teams, with Next.js App Router on the front end and Prisma connecting to Postgres on the data layer. Its distinctive point is that the application code contains no permission checks. Who can view and modify documents is written in the single file db/policy.authz, which rowstile compiles into Postgres row-level security (RLS) policies. The database filters every read and rejects writes that the rules do not allow.
The repository provides a runnable local environment: docker compose up --build starts Postgres, runs migrations (creating tables and then applying policies), and serves the app at localhost:3000. The initial data includes three users, ann, bo, and cy, with cy belonging to the writers team. The README uses these three to demonstrate sharing and permission changes.
In terms of code structure, db/policy.authz holds the rules, db/tests/sharing.authz holds rule tests (each test brings its own data and rolls back), src/db.ts executes each Prisma transaction as the requesting user, app/page.tsx and app/actions.ts contain the page and forms without checks, prisma/ stores the table schema and migrations, rowstile.toml configures the locations of policies, tests, and migrations, and the CI workflow runs the tests and comments on pull requests about who gains or loses access.
Limitations to note: requestUser currently trusts a cookie that anyone can set, and the README explicitly requires replacing it with a real session before others access the app. The passwords in docker-compose.yml, docker/init.sql, and the first migration are for local use only. The example users and team are created by the first migration and should be deleted. New tables require writing your own migration and granting permissions to starter_app, then defining types and rules in the policy; tables without rules are fully readable by the application. rowstile itself is a 0.x preview, so its language and functions may change before 1.0, and it has not been audited by anyone outside the project.
Is it right for your project?
Use Cases
- Demonstrating document sharing and team collaboration permissions based on Postgres row-level security
- Learning how to move permission rules out of application code and into database policies
- Serving as a starting point for a Next.js project that needs document sharing and fine-grained access control
- Quickly running locally with docker compose, modifying policies, and observing test feedback
Suitable For
- Developers using Next.js App Router and Prisma
- Teams that want to implement permission control with Postgres row-level security
- Projects that need a reference implementation for a document-sharing scenario
- Developers willing to accept a 0.x preview tool and replace the session and passwords themselves
Getting started & customization
Use these recorded setup notes alongside the repository instructions for your chosen version.
- 1
Run docker compose up --build to start Postgres, run migrations, and serve the app at localhost:3000
- 2
Modifying rules requires Node 22 or later and setting ROWSTILE_OWNER_DSN and ROWSTILE_APP_URL
- 3
Before using rowstile dev for the first time, run npx rowstile push --development to mark that database as a development database
- 4
The application connection uses the starter_app role; never give the application the URL of the table owner starter_owner, or row-level security will not take effect
- 5
For databases changed directly with rowstile dev, use npx prisma migrate resolve --applied to tell Prisma that the migration has been applied
License & source material
Usage conditions & limitations
Free to use · keep license noticeThis entry covers the free version in the public repository under the Apache-2.0 license; the free scope is that version's code and does not mean external services or third-party assets are free.
Must comply with when using
- Free use, modification, commercial use, and distribution are permitted; when distributing, include the Apache-2.0 license.
- Modified files must be prominently marked as changed, and relevant copyright, patent, trademark, and attribution notices must be retained.
- If the original project includes a NOTICE file, applicable attribution notices in it must be retained when distributing derivative works.
- The license includes an applicable contributor patent grant; initiating patent litigation as described in the license terminates that patent grant, and no trademark rights are granted.
- The code is provided as is; warranties and limitations of liability are governed by the original license and applicable law.
Additional costs & items to verify
- Demo images, fonts, icons, and other third-party assets must be checked against their own licenses and cannot be judged solely by the code's Apache-2.0 license.
- External services such as domains, hosting, databases, payments, or AI may incur separate charges.
- requestUser in src/db.ts trusts a cookie that anyone can set, and the "Signed in as" on the page writes that cookie. Before others access the app, both must be replaced with a real session mechanism, or identity can be forged.
- The passwords in docker-compose.yml, docker/init.sql, and the first migration are only suitable for a local laptop environment and must not be used in production or public deployments.
- The example users (ann, bo, cy) and the writers team are created by the first migration and are only for the README demonstration flow; these rows should be deleted in actual use.
- Tables without rules defined in the policy can be fully read by the application; use npx rowstile lint to list such tables and add rules.
- rowstile is in a 0.x preview stage, so its language and functions may still change before 1.0, and it has not been audited by anyone outside the project, so there is no external guarantee of stability or security.
- Never give the application the database URL of the table owner starter_owner, because row-level security does not apply to the table owner and the permission policies will fail.
View Original Text Basis
no-charge, royalty-free, irrevocable copyright license
Original License Text
`requestUser` in `src/db.ts` believes a cookie that anyone can set, and the page's "Signed in as" writes it. Replace both with your session before anyone else can reach the app.
Original README
**The passwords** in `docker-compose.yml`, `docker/init.sql` and the first migration are for a laptop.
Original README
**The people and the team** are made by the first migration, for the walk above. Delete those lines.
Original README
A table without rules is readable by the app in full; `npx rowstile lint` lists them.
Original README
rowstile is a 0.x preview: its language and its functions may still change before 1.0, and nobody outside the project has audited it
Original README
https://github.com/rowstile/starter-nextjs-prisma/blob/main/LICENSEhttps://github.com/rowstile/starter-nextjs-prisma/blob/main/README.mdNever give the app the owner's URL: row-level security doesn't apply to a table's owner.
Original README
Compiled by DeepSeek based on repository license and README ·2026-10-07. Results only cover the materials read; dependencies, images, fonts, and subsequent term changes are subject to their respective original texts.
Project checks & description sources
Template Information
- Source platforms
- GitHub
- Documentation and maintenance reference score
- More documented · 80 / 100
- Technologies
- Next.js · React
- Website type
- Starter
How this score is calculated
Our heuristic uses license records (up to 30), a demo link (12), a preview (10), stars (15), recorded maintenance (15), description completeness (8), feature records (5) and classification data (5). It is not a code, security or performance test, or a Google score. A link does not establish tested functionality.
What to verify for this project
- Repository update recorded
- 2026-10-07
- Screenshot last checked
- 2026-10-07
A demo link is listed. Check it with your own content and viewport sizes; its presence does not confirm that forms, authentication or payments work.
The catalog identifies Next.js as the primary stack. Check the actual dependency manifest and lockfile for versions and hosting requirements. These notes use recorded metadata, not a code audit or a deployment test.
Use a selection guide →How this description was prepared
AI-assisted description based on catalog records and repository material. Repository authors are not automatically the reviewers of this description.
Review declaration: [email protected] · 2026-10-08
Inspect the recorded source material
SHA-256: 876fb1c473df73b1dc20bfb5a5df4ad365799b9b194da022ecb74991d8986ea8
2026-10-07T14:20:15.865Z
Source file / repository# rowstile starter: Next.js and Prisma
Documents that people share with each other and with teams, in a Next.js app (App Router) on Prisma. There
is no permission check in the app's code. Who may see and change a document is written in one file,
[`db/policy.authz`](db/policy.authz), which [rowstile](https://rowstile.dev) compiles into Postgres row-level
security: the database filters every read and refuses every write the rules don't allow.
## Run it
docker compose up --build
That starts Postgres, runs the migrations (the tables, then the policy) and serves the app on
<http://localhost:3000>. Three people are there: ann, bo and cy, and cy is in the team "writers".
1. Sign in as **ann** and create a document.
2. Sign in as **bo**: the list is empty. The document isn't hidden by the page; Postgres doesn't return it.
3. As ann, share it with bo as a **viewer**. Bo now sees it. When he renames it, the database refuses, and
the page shows the rule and what was missing.
4. As ann, share it with the team **writers** as **editor**. Cy, a member, renames it.
## What is where
| | |
|---|---|
| [`db/policy.authz`](db/policy.authz) | the rules: who owns, who may share, what a viewer and an editor may do |
| [`db/tests/sharing.authz`](db/tests/sharing.authz) | the rules' tests: each brings its own rows and is rolled back |
| [`src/db.ts`](src/db.ts) | Prisma, signed in as the request's user on every transaction |
| [`app/page.tsx`](app/page.tsx), [`app/actions.ts`](app/actions.ts) | the page and its forms, with no checks in them |
| [`prisma/`](prisma/) | the tables, and Prisma's migrations; the policy is one of them |
| [`rowstile.toml`](rowstile.toml) | where the policy, its tests and its migrations are |
| [`.github/workflows/ci.yml`](.github/workflows/ci.yml) | the tests, and on a pull request a comment that says who gains or loses access |
Two roles connect to the database. `starter_owner` owns the tables and runs the migrations: its URL is
`ROWSTILE_OWNER_DSN`, which Prisma uses. The app connects as `starter_app` (`ROWSTILE_APP_URL`), which
row-level security applies to. Never give the app the owner's URL: row-level security doesn't apply to a
table's owner.
## Change the rules
You need Node 22 or later. With the containers up:
npm install
export ROWSTILE_OWNER_DSN=postgresql://starter_owner:owner@localhost:15432/starter
export ROWSTILE_APP_URL=postgresql://starter_app:app@localhost:15432/starter
npx rowstile push --development # once: migrations set this database up, so say it is a development one
npx rowstile dev # on every save: check, apply to this database, run the tests
Edit `db/policy.authz` (say, let an editor share: `can share = owner or editor`) and watch `rowstile dev` say
which tests now fail. When the change is what you want:
npx rowstile migrate # writes the next Prisma migration, from db/policy.lock
npm test # the app's own tests (npx prisma generate first, once)
`rowstile dev` changes this database directly, which is fine on your laptop, and it then already holds what
the new migration brings. So on this database `npx prisma migrate deploy` stops at that migration (AZ607):
tell Prisma it is applied, `npx prisma migrate resolve --applied <the new migration's folder>`. Any other
database takes migrations only. To start over, `docker compose down -v`.
## Make it yours
- **Who the request is.** `requestUser` in `src/db.ts` believes a cookie that anyone can set, and the page's
"Signed in as" writes it. Replace both with your session before anyone else can reach the app.
- **The passwords** in `docker-compose.yml`, `docker/init.sql` and the first migration are for a laptop.
- **The people and the team** are made by the first migration, for the walk above. Delete those lines.
- **Your tables.** Add them to `prisma/schema.prisma`, write their migration (with their grants to
`starter_app`), then give them a type and rules in the policy. A table without rules is readable by the
app in full; `npx rowstile lint` lists them.
rowstile is a 0.x preview: its language and its functions may still change before 1.0, and nobody outside
the project has audited it ([how it is checked](https://rowstile.dev/how-it-is-checked)). The docs:
[Next.js and Prisma](https://rowstile.dev/stacks/nextjs), [the policy language](https://rowstile.dev/reference/language),
[the cookbook](https://rowstile.dev/cookbook/).
This starter is yours to take and change: [Apache-2.0](LICENSE).
Explore similar templates
Compare previews and descriptions within the same stack and category.

Next.js SaaS Starter
The official Next.js SaaS starter template, integrating email/password authentication, Stripe Checkout subscriptions, a dashboard with user/team CRUD, basic Owner/Member RBAC, and activity logging.
Next.js · SaaS

Next.js Commerce
Vercel's officially maintained Next.js App Router ecommerce starter with deep Shopify integration, offering a complete product catalog, cart, and checkout flow. Core logic is modular for swapping backends, and community provider versions exist for BigCommerce, Medusa, and Saleor.
Next.js · E-commerce

Next-js-Boilerplate
A developer-first Next.js 16 starter with Tailwind CSS 4 and TypeScript, supporting both App Router and Page Router.
Next.js · Starter

tailwind-nextjs-starter-blog
A Next.js and Tailwind CSS blog starter template using Contentlayer for Markdown/MDX, with built-in SEO, code highlighting, and tags. It targets personal technical blogs and migration from Jekyll/Hugo to React, and supports one-click Vercel deployment.
Next.js · Blog

next-forge
next-forge is a Turborepo-based Next.js template maintained by Vercel, positioned as a starting point for SaaS products.
Next.js · Starter

SaaS-Boilerplate
SaaS-Boilerplate is an open-source SaaS starter template built with Next.js App Router, React 19, TypeScript, Tailwind CSS, and Shadcn UI.
Next.js · SaaS
