[▲ Vercel Community](/) · [Categories](/categories) · [Latest](/latest) · [Top](/top) · [Live](/live)

[Help](/c/help/9)

# Why Vercel-Neon integration uses NOLOGIN roles in preview connection URLs

33 views · 0 likes · 2 posts


Agustin Crovetto (@agcrov) · 2026-03-10

## Problem
After running a Prisma migration that creates a new PostgreSQL role with `NOLOGIN` for Row-Level Security (RLS) purposes, the Neon-Vercel integration for preview deployments started providing connection URL environment variables (`DATABASE_URL` / `POSTGRES_URL`) that reference this new `NOLOGIN` role instead of the original `default` owner role.

This causes all preview deployment builds to fail at the `prisma migrate deploy` step with:

> **Error: P1001: Can't reach database server at [ep-XXXXX.us-east-1.aws.neon.tech:5432](https://ep-xxxxx.us-east-1.aws.neon.tech:5432)**

The `NOLOGIN` role **cannot be used to authenticate** — it is designed to be assumed via `SET LOCAL ROLE` inside transactions, never for direct connections. The integration should not be selecting it as the connection role.

## Expected Behavior
The integration should continue using the original `default` role (the Neon owner role) for connection URLs in preview branches, regardless of additional roles created via migrations. At minimum, a role with `NOLOGIN` should never be selected as the connection role.

## Steps to Reproduce
1. Have the Neon-Vercel integration set up with preview environments (separate Neon branch per Vercel preview deployment).
2. Run a migration that creates a new PostgreSQL role with `NOLOGIN` and grants it table-level permissions:

```tsx
DO $$ BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'tenant_user_role') THEN
    CREATE ROLE tenant_user_role NOLOGIN;
  END IF;
END $$;

GRANT USAGE ON SCHEMA public TO tenant_user_role;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO tenant_user_role;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO tenant_user_role;

ALTER DEFAULT PRIVILEGES IN SCHEMA public
  GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO tenant_user_role;
```

3. The same migration also enables RLS on tables and creates policies (policies apply to `{public}`, i.e., all roles).
4. Push a new git branch to trigger a Vercel preview deployment.
5. The Neon integration creates a new preview branch — but the connection URL environment variables now use `tenant_user_role` instead of `default`.
6. Build fails because `tenant_user_role` has `NOLOGIN` and cannot authenticate.

## What I’ve Verified
* **The injected env var is the problem** — the connection URL provided by the integration contains the `tenant_user_role`. Manually replacing it with the original `default` role and password resolves the issue immediately.
* Table and schema ownership is correct — all tables in `public` are owned by `default`, the schema is owned by `default`, and the database ACLs show `default` as the owner:

```tsx
SELECT tablename, tableowner FROM pg_tables WHERE schemaname = 'public';
-- All rows show: tableowner = "default"

SELECT nspname, pg_catalog.pg_get_userbyid(nspowner) AS owner
FROM pg_namespace WHERE nspname = 'public';
-- owner = "default"
```

* The role is correctly `NOLOGIN` — `SELECT rolname, rolcanlogin FROM pg_roles WHERE rolname = 'tenant_user_role'` confirms `rolcanlogin = false`.
* The database is reachable — connecting via the Neon serverless driver (HTTP) with `SELECT 1` succeeds.
* Production deployments are unaffected — they use a separate Neon project.
* No role-level defaults were set — the migration does not alter `pg_db_role_setting`.

## Why the New Role Exists
The `tenant_user_role` is part of implementing Row-Level Security (RLS) for multi-tenant isolation. The application authenticates as the Neon owner role (`default`) and then assumes `tenant_user_role` via `SET LOCAL ROLE` within individual transactions. This is a standard PostgreSQL pattern.

## Environment
* Framework: Next.js 15 (App Router)
* ORM: Prisma 6.8.0
* Database: Neon Serverless PostgreSQL
* Deployment: Vercel with Neon integration for preview environments

## What I’ve Tried
* Manually overriding the connection URL with the default role and password — this works.
* Adding a keep-alive script using `@neondatabase/serverless` to ping the database via HTTP during builds.
* Redeploying multiple branches — all new preview branches exhibit the same behavior.

## Questions for the Neon Team
1. Why does the integration select a `NOLOGIN` role for the connection string? Shouldn’t `rolcanlogin = false` disqualify a role?
2. Is there a way to explicitly configure which role the integration uses for preview branch connection URLs?
3. Is this a known issue with the integration’s role detection logic when RLS is enabled?


Pauline P. Narvas (@pawlean) · 2026-03-10

Thank you for sharing so much detail, Agustin! 

Since this is a integration issue, I recommend:

* [Support - Neon Docs](https://neon.tech/docs/introduction/support#support-tickets%7CContact) Neon Support directly - they maintain the integration and can fix the role selection logic
* As a workaround, you can manually set the correct `DATABASE_URL` in your Vercel environment variables using a role that has login permissions
* You can find the correct connection string with the owner role in your Neon dashboard

When contacting Neon, mention that the Vercel integration is selecting NOLOGIN roles for preview deployments, causing Prisma migrations to fail. They’ll need to update their integration to properly filter database roles.