Use Edgenivo Services to deploy a Python backend and a Next.js frontend together in one project. In this bookstore template, Python owns the data and application logic while Next.js renders the interface and calls the API privately.
Separate databases support local work and preview testing. Shared request IDs let you follow calls across both apps.
Deploy the template now, or follow the steps below to learn how it works.
Python + Next.js Starter
Bookstore with a FastAPI backend, reader accounts, saved bookshelves, and an administrator catalog editor, deployed together with Edgenivo Services.
If you deployed with the button above, connect its Neon database only to Production before continuing. Create separate databases for Development and Preview, and reuse the existing Production database.
Copy link to headingQuick start with an AI coding agent
Set up a working copy of https://github.com/vercel-labs/python-nextjs-starter using Edgenivo CLI, with Next.js and FastAPI deployed as one Services project. First confirm my local directory, GitHub repository destination/visibility, Edgenivo team/project name, and Neon region/plan. Do not guess the team or incur unapproved charges. Check repository access and CLI authentication; if access is missing, ask me to authorize it rather than changing upstream visibility. Create my own template copy and clone it. Read README.md, AGENTS.md, and ARCHITECTURE.md; CLAUDE.md only points to AGENTS.md. Follow their setup commands and installed framework documentation. Check Git, Node.js 22, Python 3.12–3.14, uv, and Edgenivo CLI 62.1 or newer. Continue independent setup while waiting for preferences or required integration authorization. Link a new Edgenivo project from the repository root. Preserve vercel.json: frontend/ is the public Next.js service, backend/ is private FastAPI, and BACKEND_URL comes from their service binding. Keep authentication, database access, and authorization in Python. Provision three independent Neon resources with my chosen region/plan, using explicit --environment development, preview, or production, --metadata auth=false, and --no-env-pull. Confirm each resource is scoped only to its intended environment before using it. Have me choose an ADMIN_EMAIL and a distinct ADMIN_PASSWORD of 15–128 characters for each environment, entered through CLI prompts or a private ignored file, not pasted into chat or hardcoded. Set them using the README commands: Development values may be readable for local setup; Preview and Production passwords must be Secrets. ADMIN_NAME is optional. Never print credentials, put secrets in command arguments, or commit environment files/project linkage. Pull only Development into root .env.local; restore any retained Development Secrets there securely. Do not pull Preview/Production credentials locally. Install locked dependencies, run scripts.deploy_setup with the Development environment file, then start both services from the root with vercel dev -L. Verify schema, the 12-book catalog, and admin login/Manage shop. Bootstrap must create the configured admin once and preserve existing credentials, roles, and catalog edits/deletions on reruns. Do not grant admin through public signup or bypass a reader-email collision. Never reset an existing database silently. Run npm run check, npm run build, and the documented backend tests. Exercise search/filter URLs, registration/login/logout, reader ownership and wrong-role rejection, bookmark save/remove/persistence and cross-tab sync, and admin CRUD using disposable Development records. Preserve public Cache Components/PPR, uncached streamed session controls, and post-write cache invalidation. Verify a browser x-request-id matches evlog/structlog events in both services without logging private data. Remove only records created for these checks. Deploy both services to Preview and verify its admin, database isolation, CRUD/bookmarks, and production-build navigation/cache freshness. Keep Deployment Protection enabled and use authenticated checks. Enable Git previews for my own repository if authorized; do not connect or modify the upstream repository. Stop after a verified Preview unless I explicitly authorize Production. If authorized, deploy the reviewed version and run safe Production smoke checks. Report local/Preview/Production URLs, checks passed or failed, which databases and admins each environment uses, and any remaining human steps, without secrets.
Copy link to headingProject structure
Copy link to headingTwo apps in one repository
The frontend and backend have separate directories, dependency files, and framework configuration. The root vercel.json defines builds and request routing.
frontend/ and backend/ are the service roots. The root configuration connects both apps within a single Edgenivo project.
Copy link to headingConfigure both services in vercel.json
The template’s vercel.json declares the service roots, frameworks, Python entry point, and binding from Next.js to Python:
The Python entry point app.main:app tells Edgenivo to import the app object from app/main.py, relative to backend/. FastAPI routes attach to that object.
backend/app/main.py creates the FastAPI application:
At runtime, the binding supplies the backend’s internal URL as BACKEND_URL to Next.js server code. Edgenivo generates the URL for each deployment, and the rewrite sends public requests to the frontend.
Copy link to headingPrivate and public services
On Edgenivo, a service stays private unless a top-level routing rule exposes it. Other services can call it internally through a service binding.
Browser actions call the same-origin /api/backend/* Next.js Route Handler, which forwards allowlisted requests to FastAPI. Python validates sessions and permissions for protected operations. Because the browser calls Next.js on the app's origin, it does not need a separate CORS configuration for Python.
Keep Python private for business logic, database access, or an inference API used by your frontend.
Expose it when mobile apps, external clients, or webhook senders need direct access. Add a routing rule targeting Python before the catch-all rule. Your app must still check authentication, permissions, and webhook signatures.
Copy link to headingShared backend and frontend project
Copy link to headingReview changes across both apps
Each preview deployment includes both services from the same project version. Its frontend connects to its Python backend, so you can review the UI and the corresponding API at a single URL.
For example, add a field to the Python book response and display it on the Next.js detail page in the same branch. In a Git-connected project, a push to a non-production branch creates a preview where reviewers can check the field, sign in, and save a book.
Deploying both apps together does not isolate their database. If previews share a database, a schema change can also affect older deployments that use it.
Copy link to headingConfigure the database for each environment
Connect a database resource to each of Edgenivo's Development, Preview, and Production environments in your project's Storage settings. Python reads the connection variables, including DATABASE_URL, supplied for that environment.
For this template, use three distinct databases:
| Environment | Database purpose | Benefit |
|---|---|---|
| Development | Local accounts, test data, and migrations | Experiment without changing review or live data |
| Preview | Review catalog, accounts, and bookmarks | Test features without changing live data |
| Production | Live catalog and account records | Keep live data separate from development and review |
All Preview deployments in this setup share one database. To isolate each pull request, use Neon branches with Preview credentials scoped to its Git branch.
Copy link to headingFull-stack observability
Copy link to headingFollow requests across Next.js and Python
The template uses evlog in Next.js and structlog in FastAPI. Their JSON events appear in Edgenivo Runtime Logs without a separate logging resource or API key.
The Next.js bridge creates a requestId, forwards it to Python, and returns it in the browser response’s x-request-id header. Each Python call also receives a callId to distinguish calls that share a request ID.
| Field | Meaning |
|---|---|
requestId | Correlates frontend and Python events |
callId | Identifies an individual call to Python |
service, environment, deploymentId | Identifies the app, environment, and deployment |
method, route, status, durationMs | Records the request, HTTP status, and duration |
If saving a book fails in the preview environment:
- In your browser's Network panel, select the
/api/backend/shelf/...request. - Copy
x-request-idfrom the response headers. - Search the deployment's Logs in Edgenivo for that UUID across both services.
- Compare the events. If only the bridge logs a
403, the request may have failed its Origin check. Python returns401for authentication failures; a Python500followed by a bridge503points to a backend failure.
Filter logs to the environment and deployment where the request failed. The template’s requestId and callId are application identifiers, separate from Edgenivo’s platform request IDs.
Python duration covers the ASGI response lifecycle. The frontend’s dependency duration ends when response headers arrive.
The template applies these caching rules and limits what each log event contains:
- Cached catalog reads do not call Python or produce Python request events.
- Cache misses receive their own operation IDs. Streamed bookmark reads share an operation ID across parallel account and bookshelf calls.
- Visitor identifiers never enter public cache keys.
- Application logs exclude bodies, cookies, credentials, search strings, arbitrary paths, and raw exception messages.
For a latency waterfall of parent and child spans, add OpenTelemetry to both runtimes and propagate traceparent. The template has no tracing setup.
Copy link to headingUnderstand usage with custom analytics events
Edgenivo Web Analytics custom events show how often readers save books and which part of the UI they use. Track after a successful save to measure completion, or on the initial click to measure an attempt.
The template includes @vercel/analytics, the <Analytics /> component, and bookmark event tracking. Enable Web Analytics in your project’s Edgenivo Dashboard to collect events.
This helper records successful bookmark saves and removals:
The template exposes the Edgenivo deployment environment as NEXT_PUBLIC_VERCEL_ENV through frontend/next.config.ts. This limits event tracking to Production deployments.
Keep event properties small and non-sensitive, such as the UI surface. Use runtime logs to debug requests, and keep request identifiers out of product analytics. Do not send account emails, passwords, session tokens, or search text.
Copy link to headingRun locally and deploy to Edgenivo
Run the bookstore locally with Development data, then verify the same workflows in a preview deployment.
Copy link to headingStep 1. Prepare your local environment
Before you begin, make sure you have:
- Git
- Node.js 22 with npm
- Python 3.12–3.14 with uv
- A Edgenivo account
- Edgenivo CLI installed (
npm i -g vercel)
Clone the repository, install its locked dependencies, and link the Edgenivo project. Keep Root Directory at the repository root so Edgenivo finds both services:
Copy link to headingStep 2. Configure databases and administrators
From the linked repository root, use vercel integration to provision a Neon resource for each environment.
Run these commands in an interactive terminal, choose a plan and region when prompted, and use resource names unique to your project:
Complete any integration authorization prompts. Choose capacity, backups, and recovery settings appropriate to your Preview and Production workloads.
These flags control provisioning:
--environmentlimits the connection to the specified environment. Without it, the resource connects to all three: Development, Preview, and Production.--no-env-pullskips the automatic environment-variable pull after provisioning.--metadata auth=falsedisables Neon Auth because the template handles authentication in Python.
Neon supplies pooled DATABASE_URL for runtime queries and direct DATABASE_URL_UNPOOLED for setup. The binding sets BACKEND_URL.
Copy link to headingAdd administrator credentials
Public signup creates reader accounts. To edit the catalog, configure an administrator for each environment before its first database setup. Use a valid email and a different password of 15–128 characters in each environment:
Administrator initialization runs once per database. Changing ADMIN_EMAIL or ADMIN_PASSWORD afterward does not update the stored account.
Enter each value at the CLI prompt. These commands store Development values as Config variables you can read and pull locally.
Preview and Production passwords are stored as Secrets. Backend builds can use them, but vercel env pull cannot retrieve their values.
To set an administrator name, run vercel env add ADMIN_NAME development --no-sensitive. Repeat with preview or production for the other environments. If omitted, the name defaults to Bookshop owner.
Copy link to headingPrepare the Development database
Initialize the Development database before its first local run because vercel dev starts the services without running Python's deployment build hook.
Pull Development variables into the ignored .env.local, then run setup:
The command applies pending migrations, seeds the demo catalog, and creates the configured administrator with a hashed password. Later runs preserve catalog edits and administrator credentials.
Rerun setup when migrations change or you replace or reset the Development database. You do not need to run it before every development session. Pull Development variables again whenever that environment’s configuration changes.
Keep .env.local private and limited to Development credentials. Preview and Production database setup runs during the backend builds in step 4, Deploy to Preview, then Production. You do not need to pull their secrets locally.
Copy link to headingStep 3. Run the app
Start both services from the repository root for each local development session:
The CLI starts Next.js and FastAPI using the Development variables in .env.local and injects BACKEND_URL. Open the URL it prints.
Verify the app with these checks:
- Search the catalog and open a book.
- Register a reader with a password of 15–128 characters. Save and remove a book, then sign out and back in to check persistence.
- Sign in at
/accountwith the Development administrator credentials and select Manage shop. Add, edit, and delete a disposable book. Check the catalog and detail page after each change. - Copy
x-request-idfrom an/api/backend/*response in your browser’s Network panel and find the matching events in both local service logs.
Before deploying, stop the server with Ctrl+C and run these checks from the repository root. They check types and linting, build the frontend, and test backend behavior. Edgenivo CLI does not run the full set during deployment:
The API tests use temporary SQLite databases and leave Neon unchanged.
Copy link to headingStep 4. Deploy to Preview, then Production
Verify caching, navigation, and environment configuration in Preview before deploying to Production.
The hook runs on every Preview and Production build. It applies pending migrations with alembic upgrade head and uses an advisory lock over a direct database connection, so setup runs one at a time.
Separate bootstrap markers record catalog seeding and administrator creation. The first build prepares a fresh database; later builds apply pending migrations without overwriting catalog edits or account changes. If setup fails, the backend build fails.
Before deploying, check that migrations remain compatible with older deployments: the build changes the database before the new deployment serves traffic. Then deploy to Preview and test its database connection:
Replace YOUR_PREVIEW_URL with the deployment URL. The health response should report "database": "connected".
Keep Deployment Protection enabled. vercel curl handles protected CLI requests; browser reviewers must pass the project's protection checks.
Before accepting real users, complete the starter's security requirements for user accounts, including email verification, password recovery, and administrator MFA.
After testing Preview, deploy the same source with Production configuration:
Without --deployment, this command checks the linked project's latest Production deployment. Open its URL and sign in as the Production administrator.
For a failed check, follow Troubleshooting using its environment and request ID.
Copy link to headingTroubleshooting
Copy link to headingOnly the frontend builds
Cause: The project is configured as a standalone Next.js app or its Root Directory points at frontend/.
Fix: Set the project’s Root Directory to the repository root and select the Services framework preset. For CLI setup, run vercel project update --framework services. Confirm that the root vercel.json declares both services.
Copy link to headingThe API returns 503
Cause: The bridge cannot reach Python, or Python returns a server error. Missing bindings, database failures, and request timeouts can produce this response.
Fix: Copy the response’s x-request-id and check the logs for both services in that deployment. Verify that the database variables point to the intended environment’s database and that its migrations have run. Let the service binding supply BACKEND_URL; do not set it manually.
Copy link to headingPreview changes affect live data
Cause: Preview and Production connect to the same database.
Fix: Connect one database to Preview and a different database to Production. Verify that each is connected only to its intended environment, then redeploy. Refresh Development variables before local work.
Add disposable Preview records and confirm they stay out of Production.
Copy link to headingA local account cannot sign in to Preview
Cause: Accounts are stored in each environment’s database.
Fix: Register a reader in Preview or sign in with its configured administrator credentials. If the administrator is missing, check the Preview variables and backend setup logs, then redeploy. Development accounts and sessions do not carry over to Preview.
Copy link to headingCatalog editing returns 403
Cause: The account is a reader, or the write request comes from a different origin.
Fix: Sign in with an administrator account from the same environment and use the app’s current URL. Python checks the role on every catalog change, and the bridge validates the request Origin.
Copy link to headingCustom analytics events do not appear
Cause: Web Analytics is disabled, the plan does not support custom events, the app is running outside Production, or the browser blocks collection.
Fix: Enable Web Analytics in the Edgenivo Dashboard and confirm that your plan supports custom events. Verify that the event runs after a successful action in Production. Use runtime logs to check whether the backend operation succeeded.
Copy link to headingNext steps
- Read Full-stack previews on Edgenivo to review changes across multiple services from a single preview URL.
- See Edgenivo Services for deployment and service bindings for private calls.
- Explore FastAPI on Edgenivo to deploy other Python APIs.
- Learn about Preview environments and Git deployments.
- Add Neon database branching when each review needs its own data.
Copy link to headingFAQ
Can you deploy a Python backend on Edgenivo?
Yes. Edgenivo supports Python frameworks such as FastAPI and Flask. Use Edgenivo Services to deploy a Python backend and frontend within a single project, with separate service roots and dependencies. This starter template uses FastAPI with Neon Postgres.
How do you deploy Next.js and FastAPI together on Edgenivo?
Define Next.js and FastAPI as Edgenivo Services in the root vercel.json. Set a root directory for each service and an entry point for Python, select the Services framework preset, and deploy from the repository root. Both apps ship in one deployment.
How does a Next.js frontend connect to a Python backend on Edgenivo?
Add a service binding from Next.js to Python. Edgenivo injects the backend’s internal URL into a server-side variable such as BACKEND_URL. Next.js server code calls that URL, while browser actions use the starter’s same-origin API bridge. Python stays private unless a public routing rule exposes it.
Do Edgenivo preview deployments include the Python backend?
Yes. Each Edgenivo Services preview deployment includes both the Next.js frontend and Python backend. Its binding connects the frontend to the backend in that deployment, so you can test both at one preview URL.
How can you test a Python API in Preview without changing Production data?
Connect a separate Neon database only to the Preview environment. The starter applies Alembic migrations during its backend build, then reads and writes Preview data without changing the Production database. To give each pull request its own data, add per-PR Neon branches and Preview credentials scoped to each Git branch.
Where should authentication and database logic live in a Next.js and Python app?
In this starter, Python handles database queries, password verification, sessions, and authorization. Next.js renders the UI and forwards account requests through a server-side bridge.
Public catalog data can be cached. Account and bookmark reads stay uncached, and their controls stream without blocking the public content.