Next.jsReactStarter

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.

3 previews
Desktop homepage1 / 3
Desktop captureTop of page

Actual screenshot captured by the server browser.

All pages & views 3

Screenshots show visual appearance; interactive behavior may differ.

Recorded 2026-10-07View source

What stands out

A quick read of the recorded project description.

01

The application code contains no permission checks; access rules are centralized in the single file db/policy.authz

02

Rules are compiled by rowstile into Postgres row-level security policies, with filtering and rejection enforced by the database

03

Provides a one-command docker compose startup for Postgres, migrations, and the app

04

Rule tests live in db/tests/sharing.authz, and each test brings its own data and rolls back

05

The CI workflow runs the tests and comments on pull requests about who gains or loses access

06

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.

Next.jsStarter

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. 1

    Run docker compose up --build to start Postgres, run migrations, and serve the app at localhost:3000

  2. 2

    Modifying rules requires Node 22 or later and setting ROWSTILE_OWNER_DSN and ROWSTILE_APP_URL

  3. 3

    Before using rowstile dev for the first time, run npx rowstile push --development to mark that database as a development database

  4. 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. 5

    For databases changed directly with rowstile dev, use npx prisma migrate resolve --applied to tell Prisma that the migration has been applied

Read repository instructions

License & source material

Usage conditions & limitations

Free to use · keep license notice

This 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

Never give the app the owner's URL: row-level security doesn't apply to a table's owner.

Original README
https://github.com/rowstile/starter-nextjs-prisma/blob/main/LICENSEhttps://github.com/rowstile/starter-nextjs-prisma/blob/main/README.md

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).
Report a correction

Explore similar templates

Compare previews and descriptions within the same stack and category.