Optimizing the development workflow of a project is important to ship faster and better. In this article, you'll explore how to set up an optimal local development environment for a Next.js project using Neon Postgres and deploying it to Vercel.
\ The emphasis is on best practices and opinionated—thus, the article will cover local development and deployment, branching, and environments by examining a CRUD application that displays a list of user details from a database.
In more details, we'll cover:
\
The requirements for following this guide are as follows:
\ With that out of the way, let's work on the project setups for Neon and Vercel.
How to set up a Neon Postgres projectNeon is a serverless Postgres that separates computing and storage. It offers modern developer features such as autoscaling, branching, and point-in-time restore, allowing scalable and faster development.
\ Create a free Neon account if you still need to do so. Once done, Neon redirects you to a project setup page, where you must provide a project and database name, a Postgres version, and a region (we recommend selecting one close to your location) intended for the project.
\
\ Neon provides a CLI tool for integration with your local environment, but this article will use Neon through its web interface for certain operations.
\ Once you have created your project, copy the pooled connection string from the Neon Dashboard interface and paste it into a .env.production file within your Next.js project.
\
Speaking of the Next.js project, this article will use a current working Next.js project containing a data table from ShadcnUI.
To get this project, clone this repository to your local machine using the command.
\
git clone https://github.com/muyiwexy/dev_env_hackmamba.git\ Once you've cloned the repository, create a .env.production file to house environment variables in the project's main directory and paste your connection string. It should look like this:
\
DATABASE_URL = 'postgresql://neondb_owner:**************-withered-sea-a5nyklf9.us-east-2.aws.neon.tech/neondb?sslmode=require'\ Next, proceed to the Neon SQL editor in the Neon dashboard. Here, you can paste SQL commands to perform specific actions needed for your project. Copy and paste the command below to the editor to create an SQL table with some required fields:
\
CREATE TABLE user_details ( member_number VARCHAR(10) PRIMARY KEY, created_at VARCHAR, name VARCHAR(100), email VARCHAR(255), phone_number VARCHAR(15), gender VARCHAR(10), zone VARCHAR(50), service_unit VARCHAR(100), conference_shirt VARCHAR(5), fee_payment VARCHAR(20), paid BOOLEAN );\
Note: You can find this command in the /sql/user_data.sql file within the Next.js template provided earlier.
\
\ You can check the Tables section anytime to confirm if the newly created table is available. Now that you have that information, you'll deploy your application to Vercet. You can do that through Vercel's web user interface, but we'll use the Vercel CLI for this tutorial.
Deploying your Next.js app to VercelWithout wasting much time, head to your terminal and paste the command below:
\
npm i -g vercel\
Note: For Mac users, you might sometimes get an access denied error; thus, prefix the command with the sudo keyword.
\ The command installs the CLI globally, allowing easy access to the CLI anywhere across your local machine.
The next thing to do is log in to your Vercel account using the CLI. To achieve that, paste the command below in your terminal:
\
vercel login\ Follow up by choosing your Vercel sign-up provider from the list, authenticating, and looking for the success message on the confirmation page.
\
Next, you will deploy your program to Vercel using the command below:
\
vercel\ This process involves several steps to set up your deployment. To ensure uniformity, follow the choices in the image below.
\
\
Note: After building, you can check the deployment to confirm if your app is running as expected
\ Next, this article will show how to use a Vercel Edge function to retrieve user information from a Neon database.
Creating a Vercel edge functionVercel Edge Functions are performance enhancers. They are JavaScript or TypeScript functions that are more efficient and faster than traditional serverless computing because of their leaner runtime operations.
\ Return to your cloned project and create a /api/route.ts file within the /app directory. To run this function at the edge, specify a runtime in the code base as follows:
\
import { NextRequest, NextResponse } from "next/server"; export const runtime = "edge"; export async function GET(req: NextRequest, res: NextResponse) { return NextResponse.json({ message: "Hello from the Edge!" }); }\ Before proceeding, you will install the Neon serverless driver, Zod, and sqlstring package using the command:
\
npm install @neondatabase/serverless zod sqlstring\ Also, you must install sqlstring types as a dev dependency using the command below.
\
npm i --save-dev @types/sqlstring -D\ You can test if there's a successful connection to your database by replacing the code in the /api/route.ts file with the code below:
\
import { NextRequest, NextResponse } from "next/server"; import { Pool } from "@neondatabase/serverless"; export const runtime = "edge"; export async function GET(req: NextRequest) { const pool = new Pool({ connectionString: process.env.DATABASE_URL, }); const sql = ` SELECT NOW(); `; const { rows } = await pool.query(sql); const now = rows[0]; await pool.end(); return NextResponse.json( { now }, { status: 200, } ); }\ You should get a response like the image below when you access the /api route in the browser.
\
\ The next thing to do is add your database connection string to Vercel's environment variables. So, using the Vercel CLI, add this string using the command:
\
vercel env add\ Follow the prompts to add the variable name (we recommend you use the name in your .env.production) and value (the value should be the string itself). Next, select the environment where you want to utilize the variable between production, preview, and development.
\
Note: We will explore branching later, so creating multiple connection strings is unnecessary.
\ Now that you have added your database URL to your project, redeploy using the command:
\
Vercel\ In the next section, you'll get to send some data to Neon using a POST request from your function API route.
Sending data to NeonIt is difficult to understand any of these concepts without working with data. So, let's send some dummy data to a Neon database. This section will cover SQL injection and attack prevention on the database using Zod. We will also discuss database branching, which gives us more flexibility and protects the credibility of your production branch.
\ Let's explore this API route handler function for processing an HTTP POST request by pasting the code below into /api/route.ts.
\
export async function POST(req: any) { try { const data = await req.json(); const { member_number, created_at, name, email, phone_number, gender, zone, service_unit, conference_shirt, fee_payment, paid, } = schema.parse(data); const sql = sqlstring.format( ` INSERT INTO user_details ( member_number, created_at, name, email, phone_number, gender, zone, service_unit, conference_shirt, fee_payment, paid ) VALUES (?,?,?,?,?,?,?,?,?,?,?) `, [ member_number, created_at, name, email, phone_number, gender, zone, service_unit, conference_shirt, fee_payment, paid, ] ); console.log("sql", sql); await pool.query(sql); await pool.end(); return NextResponse.json(data); } catch (error) { console.error("Error processing request:", error); return NextResponse.json( { message: "Failed to save user details" }, { status: 500 } ); } }\ This Edge function destructures the form values with these details: member_number, created_at, name, email, phone_number, gender, zone, service_unit, conference_shirt, fee_payment, paid from the request JSON. Next, you validate the form data with Zod. To do this, paste the code below into the /api/route.ts
\
const schema = zod.object({ member_number: zod.string().min(5).max(12), created_at: zod.string(), name: zod.string().min(1, "Name is required").max(100, "Name is too long"), email: zod .string() .email("Invalid email format") .min(5, "Email is too short") .max(100, "Email is too long"), phone_number: zod .string() .min(7, "Phone number is too short") .max(15, "Phone number is too long"), gender: zod .string() .min(1, "Gender is required") .max(6, "Gender is too long"), zone: zod.string().min(1, "Zone is required").max(50, "Zone is too long"), service_unit: zod .string() .min(1, "Service Unit is required") .max(50, "Service Unit is too long"), conference_shirt: zod .string() .min(1, "Conference shirt size is required") .max(5, "Conference shirt size is too long"), fee_payment: zod .string() .min(1, "Fee Payment info is required") .max(50, "Fee Payment info is too long"), paid: zod.boolean(), });\ The code above defines a schema that describes the structure and validation rules for an object representing the form data. Now, you can successfully make an INSERT query to the database.
\ It should look like the image below when you check your database.
\
\ Smooth and quick—with that, you can populate your Neon database. The question now is, what if this is a production database? It is unwise to use test data in a production environment. Neon has evolved to allow us to create branches (similar to how GitHub branches work) for your database. Now, you can quickly test and develop your app without any drawbacks or fear of contaminating the production database.
\ In the next section, this article will explore database branching with Neon.
Database branching in NeonHead to the Branches section in the Neon console and select Create branch. You must name a branch with the main branch as the parent when creating it. One thing that caught our attention was that it allowed us to put the data we wanted in the branch by period, ensuring more flexibility.
\
After creating a branch, you will receive a connection string, just as you did when creating a project; make sure to keep it in a safe location.
\
Remember, this branch is a separate database with actual data as the main branch.
\ To use this new database connection string, create a .env.local file similar to the .env.production file you created and set up the DATABASE_URL credential with the connection string as its value.
\
Next.js automatically detects what environment file to use during development or production.
\ When you test the database branch table with new data, you can compare it with the production branch.
\
You can make as many alterations to the branch as you like, such as changing the table schema or deleting data.
ConclusionDevelopment can be complicated, but with the tools provided by Neon Postgres, building scalable and reliable applications is faster. This article provided a detailed guide on setting up a local development environment using Neon and deploying it to Vercel. We covered essential aspects such as local development setups, deployment processes, branching, and managing different environments. Continue application development with this setup; we'd love to hear how it's going.
\ You can check out the entire project on GitHub.
All Rights Reserved. Copyright , Central Coast Communications, Inc.