The first Vercel deployment decision is the application root and build contract, not copying every local directory to a server. My NextPortfolio archive contains Next.js, Prisma and Vercel configuration. This guide examines those decisions and uses a smaller configuration example to explain a preview-to-production workflow.
It does not claim that a real Vercel project was created or that the older application deployed successfully. Example JSON and the health handler are checked locally. The current Angular/.NET process model belongs to the Render guide; adding vercel.json does not turn that .NET API into a Next.js function.
Select the actual Next.js application root
Import the Git repository, confirm the Next.js framework preset and set Root Directory to the folder containing the real Next.js package.json. Do not accidentally select a tutorial folder or this Angular project as the Next.js application. Its lockfile and framework configuration must agree with that root.
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"framework": "nextjs",
"installCommand": "npm ci",
"buildCommand": "npm run build"
}
This file belongs at the Next.js project root. It does not force a generic dist output directory because the framework controls its deployment artifacts. The archived vercel.json also contains builds and PRISMA_GENERATE_DATAPROXY. The example does not carry them forward without an established requirement. An old Data Proxy flag is not a fix for an ordinary PostgreSQL connection.
Generate Prisma Client during the build
{
"scripts": {
"dev": "next dev",
"build": "prisma generate && next build",
"start": "next start",
"typecheck": "tsc --noEmit"
}
}
Merge this fragment into an existing package.json scripts section; it is not a complete application manifest. Running prisma generate at build start avoids relying on a cached client after schema changes. prisma and @prisma/client must be installed in compatible versions. A build installation that omits necessary development tools can make the command unavailable.
generate does not create tables or apply production migrations. A preview deployment should not automatically run migrate dev, db push or seed against production. Schema changes need a controlled deployment step, and reverting code does not automatically revert them. The archive contains settings that skip TypeScript/lint failures; a green build with those settings is not a substitute for type checking and relevant tests.
Keep Prisma 6 and Prisma 7 setup distinct
// Prisma 6-style fragment; actual models are defined separately.
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}
This fragment illustrates the Prisma 6-style generator/datasource contract in NextPortfolio; its actual models are separate. The archive uses the 6.15 client family. The standalone Prisma article instead uses 7.10.1, prisma.config.ts and a pg adapter. Combining both setups into one file would obscure the version boundary.
With a Rust-engine client, the generated engine must match the actual Vercel Node/OS/OpenSSL environment. An older binaryTargets value should not survive merely because the app worked locally. Confirm the package and target runtime. Moving to a driver adapter also requires a compatible Prisma version, adapter and pool configuration rather than one isolated generator change.
Configure Production, Preview and Development independently
# Prisma 6 runtime. URI-encode the password and CA path.
DATABASE_URL="postgresql://postgres.YOUR_REF:YOUR_PASSWORD@YOUR_POOLER:6543/postgres?pgbouncer=true&connection_limit=1&sslmode=require&sslaccept=strict&sslcert=YOUR_ENCODED_CA_PATH"
# CLI: direct or Session pooler, with separately verified TLS.
DIRECT_URL="postgresql://postgres.YOUR_REF:YOUR_PASSWORD@YOUR_POOLER:5432/postgres?sslmode=require&sslaccept=strict&sslcert=YOUR_ENCODED_CA_PATH"
# Example auth integration name; configure the actual library separately.
AUTH_SECRET=YOUR_RANDOM_SERVER_SECRET
# Safe public URL only; not a secret key.
NEXT_PUBLIC_SITE_URL=https://portfolio.example.com
The values are placeholders. Assign each setting to its intended Vercel environment. A preview must not inadvertently become another administrator application with production write access: use separate development data, limited credentials and, where appropriate, a separate Supabase project/schema. A different deployment URL alone does not create another database.
AUTH_SECRET is an illustrative setting for the Next.js authentication integration, not PortfolioBlog's Admin__PasswordHash system. The actual auth library determines required names and callback URLs. Never prefix SQL passwords, authentication secrets or Storage server keys with NEXT_PUBLIC_: Next.js can include such values in browser code.
Editing a dashboard variable does not rewrite an existing deployment; redeploy with the intended settings. Public values read during build can be embedded into the output. A local .env.local file also does not populate the remote project automatically, and files pulled by the CLI remain outside source control.
Match Supabase pooling to function lifetimes
The Prisma 6 runtime example uses Supabase Transaction pooler/6543 with pgbouncer=true. connection_limit=1 is a starting budget, not a universal performance prescription. DIRECT_URL separates CLI/schema operations onto a direct or suitable Session/5432 endpoint. Verify certificate options with the provider CA and encode passwords and certificate URI paths correctly.
One shared client inside an instance does not mean one database connection for the entire deployment. Parallel instances and previews multiply pools. Reuse a client for the appropriate module/process lifetime instead of creating and disconnecting one on every request, then budget total connections. Prisma 7 pg-adapter behavior must not be inferred from older URI pool parameters.
// Merge into the existing Next.js configuration; keep its other options.
export default {
outputFileTracingIncludes: {
'/*': ['./config/supabase-ca.crt'],
},
};
A CA file on the development machine does not necessarily reach the function bundle. Merge this tracing option into the existing Next.js configuration and include the public certificate at config/supabase-ca.crt. Check the certificate path independently for the CLI and runtime working directories. It contains no private key; a server API secret does not belong in this file.
import 'server-only';
import { PrismaClient } from '@prisma/client';
const cache = globalThis as typeof globalThis & { prisma?: PrismaClient };
export const prisma = cache.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== 'production') cache.prisma = prisma;
This older client pattern belongs in a server-only module, never a React Client Component. Apply publication/deletion filters in public server queries. A privileged SQL connection does not automatically carry an end-user Supabase identity, and admin routes still need authorization. Generated types do not prove that an HTTP caller is permitted to act.
Add a small Node route handler
// Place at src/app/api/health/route.ts in a Next.js App Router application.
export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';
export function GET(): Response {
return Response.json(
{ status: 'ok' },
{ headers: { 'Cache-Control': 'no-store' } },
);
}
Place this file at src/app/api/health/route.ts. runtime=nodejs and force-dynamic make the example's execution intent explicit, and its response is not cached. This handler does not test SQL connectivity. Read real public content as well before concluding that the database integration works.
Review payload limits and filesystem assumptions
Vercel Functions currently documents a 4.5 MB request/response payload limit. PortfolioBlog permits a 5 MiB image inside a 6 MiB multipart envelope. Proxying the same upload through a Function can therefore exceed the platform limit; increasing an ASP.NET setting does not change that limit. Upload architecture requires a separate decision.
Options include preserving the authorized upload path to the Render API or issuing a limited, server-authorized direct-upload capability for Storage. The latter does not mean shipping the server secret key to the browser. Writing an image to a function's local filesystem is not durable media storage either. Authorization, size/type validation, object naming and retries need to be considered together.
Move from preview to production deliberately
# In the intended Next.js project; these commands need Vercel access.
vercel link
vercel env pull .env.local --environment=development
npm ci
npm run typecheck
npm run build
# Preview deployment, then review before production:
vercel
vercel --prod
These are deployment instructions, not commands executed to create a live deployment while writing the article. Link and environment operations must target the correct Vercel project. Inspect the home page, direct article URLs, both languages, admin protection, a data read and failure behavior in preview. Evaluate production-specific settings before assigning the production domain.
For a custom domain, apply the DNS records provided by the project dashboard rather than copying an arbitrary IP. Generate production canonical metadata from a trusted origin. A preview URL should not accidentally become the permanent canonical URL or be indexed as production content. DNS, TLS and application metadata are separate checks within that change.
When the build passes but the page fails
- For a stale client, confirm that generation ran against the intended schema.
- For preview-only failures, inspect environment assignments and callback URLs rather than assuming production settings are shared.
- For engine or connection errors, check the actual package/runtime, pooler and TLS settings. Keep certificate validation enabled.
- For a 413, separate application and platform payload limits. Treat 401/403 as authorization failures.
- After rollback, verify older-code/newer-schema compatibility; the database was not automatically rolled back.
Vercel's Next.js flow uses a framework-aware build and request model. Decisions made while starting my own processes on Render do not all transfer unchanged. Both guides ultimately verify deployment against the intended content, authorization and environment.