Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      10 Ways Node.js Development Boosts AI & Real-Time Data (2025-2026 Edition)

      August 18, 2025

      Looking to Outsource React.js Development? Here’s What Top Agencies Are Doing Right

      August 18, 2025

      Beyond The Hype: What AI Can Really Do For Product Design

      August 18, 2025

      BrowserStack launches Chrome extension that bundles 10+ manual web testing tools

      August 18, 2025

      ML Observability: Bringing Transparency to Payments and Beyond

      August 18, 2025

      Highlights from Git 2.51

      August 18, 2025

      3D Layered Text: The Basics

      August 18, 2025

      CodeSOD: Going Crazy

      August 18, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      Optimizely Mission Control – Part II

      August 18, 2025
      Recent

      Optimizely Mission Control – Part II

      August 18, 2025

      AI: Security Threat to Personal Data?

      August 18, 2025

      Live Agent Transfer in Copilot Studio Using D365 Omnichannel – Step-by-Step Implementation

      August 18, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      Access Root Directory in Nautilus File Manager

      August 18, 2025
      Recent

      Access Root Directory in Nautilus File Manager

      August 18, 2025

      Ptyxis: Ubuntu’s Leap Into GPU-Powered Terminals

      August 18, 2025

      Raspberry Pi Unveils $40 Five-Inch Touch Display 2

      August 18, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Development»How to Deploy a Next.js API with PostgreSQL and Sevalla

    How to Deploy a Next.js API with PostgreSQL and Sevalla

    August 18, 2025

    When developers think of Next.js, they often associate it with SEO-friendly static websites or React-based frontends. But what many miss is how Next.js can also be used to build full-featured backend APIs – all within the same project.

    I’ve recently written an article on working with Next.js API and deploying it to production. In this case, I would’ve used a JSON file as a mini-database.

    But JSON or any type of file storage isn’t fit for a production application. This is because file-based storage isn’t designed for concurrent access, so multiple users writing data at the same time can cause corruption or loss.

    It also lacks indexing and query capabilities, making it slow as data grows. Backups, security, and scalability are also harder to manage compared to a proper database.

    In short, while JSON files work for demos or prototypes, production systems need a database that can handle concurrency, large datasets, complex queries, and reliable persistence.

    So in this article, we’ll walk through how to build a REST API with Next.js, store data in a Sevalla-managed database, and deploy the whole project to production using Sevalla’s PaaS infrastructure.

    Table of Contents

    • What is Next.js?

    • Installation and Setup

    • How to Build a NextJS API

    • Provisioning a Database in Sevalla

    • Deploying to Sevalla

    • Conclusion

    What is Next.js?

    Next.js is an open-source React framework developed by Vercel. It’s known for server-side rendering, static generation, and seamless routing. But beyond its frontend superpowers, it allows developers to build backend logic and APIs through its file-based routing system. This makes Next.js a great choice for building full-stack apps.

    Installation and Setup

    To get started, make sure Node.js and NPM are installed.

    $ node --version
    v22.16.0
    
    $ npm --version
    10.9.2
    

    Now, create a new Next.js project:

    npx create-next-app@latest
    

    The result of the above command will ask you a series of questions to setup your app:

    What is your project named? my-app
    Would you like to use TypeScript? No / Yes
    Would you like to use ESLint? No / Yes
    Would you like to use Tailwind CSS? No / Yes
    Would you like your code inside a `src/` directory? No / Yes
    Would you like to use App Router? (recommended) No / Yes
    Would you like to use Turbopack for `next dev`?  No / Yes
    Would you like to customize the import alias (`@/*` by default)? No / Yes
    What import alias would you like configured? @/*
    

    But for this tutorial, we aren’t interested in a full stack app – just an API. So let’s re-create the app using the — - api flag.

    $ npx create-next-app@latest --api
    

    It will still ask you a few questions. Use the default settings and finish creating the app.

    9f1d2763-7df5-491b-8cb3-05161b35fbd9

    Once the setup is done, you can see the folder with your app name. Let’s go into the folder and run the app.

    $ npm run dev
    

    Your API template should be running at port 3000. Go to http://localhost:3000 and you should see the following message:

    {
    "message": "Hello world!"
    }
    

    How to Build a NextJS API

    Now that we’ve set up our API template, let’s write a basic REST API with two endpoints: one to create data and one to view data

    The API code will reside under /app within the project directory. Next.js uses file-based routing for building URL paths.

    For example, if you want a URL path /users, you should have a directory called “users” with a route.ts file to handle all the CRUD operations for /users. For /users/:id, you should have a directory called [id] under “users” directory with a route.ts file. The square brackets are to tell Next.js that you expect dynamic values for the /users/:id route.

    Here is a screenshot of the setup. Delete the [slug] directory that comes with the project since it won’t be relevant for us.

    Folder setup

    • The route.ts file at the bottom handles CRUD operations for / (this is where the response “hello world” was generated from)

    • The route.ts file under /users handles CRUD operations for /users

    While this setup can seem complicated for a simple project, it provides a clear structure for large-scale web applications. If you want to go deeper into building complex APIs with Next.js, here is a tutorial you can follow.

    The code under /app/route.ts is the default file for our API. You can see it serving the GET request and responding with “Hello World!”:

    import { NextResponse } from "next/server";
    
    export async function GET() {
      return NextResponse.json({ message: "Hello world!" });
    }
    

    Now we need two routes:

    • GET /users which lists all users

    • POST /users which creates a new user

    For this project, we’ll use a database to store our records. We’re not going to install a database on our local machine. Instead, we’ll provision the database in the cloud and use it with our API. This approach is common in test / prod environments to ensure data consistency.

    Provisioning a Database in Sevalla

    Sevalla is a modern, usage-based Platform-as-a-service provider and an alternative to sites like Heroku or to your self-managed setup on AWS. It combines powerful features with a smooth developer experience.

    Sevalls offers application hosting, database, object storage, and static site hosting for your projects. It comes with a generous free tier, so we’ll use it to connect to a database as well as deploy our app to the cloud.

    If you are new to Sevalla, you can sign up using your GitHub account to enable direct deploys from your GitHub. Every time you push code to your project, Sevalla will auto-pull and deploy your app to the cloud.

    Once you login to Sevalla, click on “Databases”.

    Sevalla Databases

    Now let’s create a PostgreSQL database.

    Create Postgresql Database

    Use the default settings. Once the database is created, it will disable the external connections by default for security to ensure no one outside our server can connect to it. Since we want to test our connection from our local machine, let’s enable an external connection.

    Database settings

    The value we need to connect to the database from our local endpoint is “url” under external connection. Create a file called .env in the project and paste the URL in the below format:

    PGSQL_URL=postgres://<username>:<password>-@asia-east1-001.proxy.kinsta.app:30503/<db_name>
    

    The reason we use .env is to store environment variables specific to the environment. In production, we won’t need this file (never push .env files to GitHub). Sevalla will give us the option to add environment variables via the GUI when we deploy the app.

    Now let’s test our database connection. Install the pg package for Node to interact with PostgreSQL. Let’s also install the TypeScript extension for pg to support TypeScript definitions.

    $ npm i pg
    $ npm install --save-dev @types/pg
    

    Change the route.ts that served “hello world” to the below:

    // app/api/your-endpoint/route.ts
    import { NextResponse } from "next/server";
    import { Client } from "pg";
    
    export async function GET() {
      const client = new Client({
        connectionString: process.env.PGSQL_URL,
      });
    
      try {
        await client.connect();
        await client.end();
        return NextResponse.json({ message: "Connected to database" });
      } catch (error) {
        console.error("Database connection error:", error);
        return NextResponse.json({ message: "Connection failed" }, { status: 500 });
      }
    }
    

    Now when your app and go to localhost:3000, it should say “connected to database”.

    Postgresql successful connection

    Great. Now let’s write our two routes, one to create data and the other to view the data we created. Use this code under users/route.ts:

    import { NextResponse } from "next/server";
    import type { NextRequest } from "next/server";
    import { Client } from "pg";
    
    // Define the structure of a User object
    interface User {
      id: string;
      name: string;
      email: string;
      age: number;
    }
    
    // Create a PostgreSQL client
    function getClient() {
      return new Client({
        connectionString: process.env.PGSQL_URL,
      });
    }
    
    // Fetch all users from the database
    async function readUsers(): Promise<User[]> {
      const client = getClient();
      await client.connect();
    
      try {
        const result = await client.query("SELECT id, name, email, age FROM users");
        return result.rows;
      } finally {
        await client.end();
      }
    }
    
    // Insert or update users in the database
    async function writeUsers(users: User[]) {
      const client = getClient();
      await client.connect();
    
      try {
        const insertQuery = `
          INSERT INTO users (id, name, email, age)
          VALUES ($1, $2, $3, $4)
          ON CONFLICT (id) DO UPDATE SET
            name = EXCLUDED.name,
            email = EXCLUDED.email,
            age = EXCLUDED.age;
        `;
    
        for (const user of users) {
          await client.query(insertQuery, [user.id, user.name, user.email, user.age]);
        }
      } finally {
        await client.end();
      }
    }
    
    // Handle GET request: return list of users
    export async function GET() {
      try {
        const users = await readUsers();
        return NextResponse.json(users);
      } catch (err) {
        console.error("Error reading users from DB:", err);
        return NextResponse.json({ error: "Failed to fetch users" }, { status: 500 });
      }
    }
    
    export async function POST(req: NextRequest) {
      try {
        const body = await req.json();
        const users: User[] = Array.isArray(body) ? body : [body];
    
        await writeUsers(users);
    
        return NextResponse.json({ success: true, count: users.length });
      } catch (err) {
        console.error("Error writing users to DB:", err);
        return NextResponse.json({ error: "Failed to write users" }, { status: 500 });
      }
    }
    

    Now when you go to localhost:3000/users, it will give you an error because the users table does exist. So let’s create one.

    In the database UI, click on “Studio”. You’ll get a visual editor for your database where you can manage your data directly (pretty cool, right?).

    Database studio

    Press the “+” icon and choose “create table”. Create the table with the schema below. Click the “add column” link to create new columns.

    Database Schema

    Click “create table and you should see the table created as below:

    Users table

    Let’s add a dummy record using “add record” button to use it to test our API. The id field should be in UUID format (and you can generate one here).

    Now let’s test our API.

    3fd9784e-3a83-415d-870f-f3f5d23dec51

    You should see the user you created as the response to the localhost:3000/users query. Now let’s create a new user using our API.

    We’ll use Postman for this since its easy to create POST requests using Postman. We’ll send a sample data under “body” → “raw” → “JSON”.

    Post Request

    The response from Postman should be as below:

    Postman results

    Now going to localhost:3000/users, you should see the new record created.

    Get /users

    Great job! Now let’s get this app live.

    Deploying to Sevalla

    Push your code to GitHub or fork my repository. Now lets go to Sevalla and create a new app.

    Sevalla create app

    Choose your repository from the dropdown and check “Automatic deployment on commit”. This will ensure that the deployment is automatic every time you push code. Choose “Hobby” under the resources section.

    Sevalla Create New App

    Click “Create” and not “Create and deploy”. We haven’t added our PostgreSQL URL as an environment variable, so the app will crash if you try to deploy it.

    Go to the “Environment variables” section and add the key “PGSQL_URL” and the URL in the value field.

    7525c6cd-63af-40b2-80c5-6b49b6101f19

    Now go back to the “Overview” section and click “Deploy now”.

    c3f12f86-0732-4518-bf51-4867ac86abdd

    Once deployment is complete, click “Visit app” to get the live URL of your API. You can replace localhost:3000 with the new URL in Postman and test your API.

    Congratulations – your app is now live. You can do more with your app using the admin interface, like:

    • Monitor the performance of your app

    • Watch real-time logs

    • Add custom domains

    • Update network settings (open/close ports for security, and so on)

    • Add more storage

    Conclusion

    Next.js is no longer just a frontend framework. It’s a powerful full-stack platform that lets you build and deploy production-ready APIs with minimal friction. By pairing it with Sevalla’s developer-friendly infrastructure, you can go from local development to a live, cloud-hosted API in minutes.

    In this tutorial, you learned how to set up a Next.js API project, connect it to a cloud-hosted PostgreSQL database on Sevalla, and deploy everything seamlessly. Whether you’re building a small side project or a full-scale application, this stack gives you the speed, structure, and scalability to move fast without losing flexibility.

    Hope you enjoyed this article. I’ll see you soon with another one. You can connect with me here or visit my blog.

    Source: freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More 

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleCreating a Real-Time Gesture-to-Text Translator Using Python and Mediapipe
    Next Article How to Build an Always Listening Network Connectivity Checker in Flutter using BLoC

    Related Posts

    Development

    How to Build an Always Listening Network Connectivity Checker in Flutter using BLoC

    August 18, 2025
    Development

    Creating a Real-Time Gesture-to-Text Translator Using Python and Mediapipe

    August 18, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    CVE-2024-48906 – Sematell ReplyOne Cross-Site Scripting Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    Amazon’s AI Boom Collides with Climate Pledge: Carbon Emissions Soar 6%

    Security

    Scaling Reinforcement Learning Beyond Math: Researchers from NVIDIA AI and CMU Propose Nemotron-CrossThink for Multi-Domain Reasoning with Verifiable Reward Modeling

    Machine Learning

    CVE-2025-5792 – TOTOLINK EX1200T HTTP POST Request Handler Buffer Overflow Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    Highlights

    Citrix Warns of Privilege Escalation Vulnerability in Windows Virtual Delivery Agent (CVE-2025-6759)

    July 9, 2025

    Citrix Warns of Privilege Escalation Vulnerability in Windows Virtual Delivery Agent (CVE-2025-6759)

    Citrix has issued a security advisory concerning a newly identified local privilege escalation vulnerability affecting its Windows Virtual Delivery Agent (VDA), which is a core component of Citrix Vir …
    Read more

    Published Date:
    Jul 09, 2025 (6 hours, 6 minutes ago)

    Vulnerabilities has been mentioned in this article.

    CVE-2025-6759

    CVE-2025-6543

    CVE-2024-8535

    CVE-2024-8534

    CVE-2024-6387

    CVE-2025-4857 – WordPress Newsletters Plugin Local File Inclusion Vulnerability

    May 31, 2025

    CVE-2025-3819 – PHPGurukul Men Salon Management System SQL Injection Vulnerability

    April 20, 2025

    Best AI-Powered Tools to Build Your Next Project Faster

    April 21, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.