Skip to content

Deploy Next.js with PostgreSQL

Take a Next.js app from GitHub to your own domain, with a PostgreSQL database beside it.

Updated

This tutorial takes a Next.js application from a GitHub repository to an HTTPS address on your own domain, with a PostgreSQL database beside it. It uses only the console.

Before you start

You need:

  • A Next.js application in a GitHub repository, with build and start scripts in its package.json, as create-next-app writes them. The tutorial assumes it reads its database address from DATABASE_URL.

  • An organization whose workspace is ready: its Projects page shows New project. If it reads "Your workspace is still being prepared.", see Workspace still being prepared.

  • A card on that organization, unless both services stay within the free allowance. The application is charged by the hour while it runs, and the database by the data it holds; each form's Order summary shows the rate before you create anything, and Billing explains the free allowance and how each month is paid.

  • For the last part, a domain whose DNS records you can edit, such as www.example.com.

1. Connect GitHub

Open Settings, then Git providers, and press Connect. On GitHub, install the Cahaves GitHub App on the account that owns the repository, and give it access to that repository. GitHub sends you back to Git providers, where the account is now listed.

Finish within 15 minutes of pressing Connect. Deploy from GitHub covers the install in detail.

2. Create a project

Open Projects and press New project. Give it a Name of up to 60 characters, such as Shop, and press Create project. The project's page opens, empty.

3. Add the database

  1. Open the PostgreSQL form

    On the project, press Add a service. Under Databases, press Create on PostgreSQL.

  2. Fill it in

    Keep the newest Version unless your application needs another; a database cannot be moved to another version afterwards. Keep Name (postgres), Database name (app) and Username (app), or change them now: they are fixed once the database first starts. The Password is generated in your browser; Generate another draws a new one. Keep Automatic backup on Daily.

    If the form reads "Automatic backups unavailable", the platform has no backup storage configured. You can still create the database, without automatic backups.

  3. Create and start it

    Press Create service. The database's page opens. A database starts only when it is deployed, so press Deploy. The deployment reads Done once the database is running, within two minutes.

On the database's Overview, the Connection card shows its Internal address: a full postgresql:// address with the user, the password, the host and the port filled in. You will copy it with its copy button in step 6. PostgreSQL covers the rest of the card.

4. Add the application

  1. Open the GitHub form

    Back on the project, press Add a service. Under Applications, press Create on Git repository (GitHub App).

  2. Choose the repository

    Choose the Account, the Repository and the Branch. Cloud reads the repository, and Build with should read nixpacks with the line "From the repository: package.json, with pnpm." The manager named is the one your lock file belongs to: pnpm, Yarn, Bun or npm.

  3. Name it and create it

    Name it web, choose a Size, and press Create service. The service's page opens. Nothing is deployed yet.

On the service's Overview, the Source card shows what Cloud read: an Install command such as pnpm install --frozen-lockfile, a Build command such as pnpm run build, and a Start command such as pnpm run start. Build settings explains each.

5. Check the port

Open the service's Settings section. Port reads 3000, which is the port next start listens on unless your start script names another. If your start script passes a different port, such as next start -p 8080, set Port to it and press Save settings.

Do this before the first deploy. The address Cloud generates at the first deploy keeps the port the service had then, and Domains explains what changing it later involves.

6. Set the environment

Open the Environment section.

  • If your repository has a .env.example, the section opens in editing mode with the line "Filled in from .env.example. Nothing is saved until you save it." Replace each example value with the real one.

  • Otherwise press Edit.

Set DATABASE_URL to the database's Internal address, copied from its Connection card:

Environmentdotenv
DATABASE_URL=postgresql://app:<password>@<engine name>:5432/app

Press Save. The service has not run yet, so nothing restarts; it starts with this environment at its first deploy. Environment variables explains what happens when you change it later.

The build sees the same environment

DATABASE_URL is set while next build runs as well as while the application runs. Cloud builds on a shared build server, separate from the machines your services run on, and this tutorial assumes nothing reads the database during the build.

7. Deploy

Press Deploy in the service's header. The deployment's page opens and its Build log streams as the build runs. The status moves through Queued, Starting and Deploying, and ends Done once a container of the application is running.

If the build fails with "No start command could be found", your package.json has no start script. Set Start command on the Source card, such as npm run start with your own manager, press Save source, and deploy again.

If the deployment reads Done and the service's Overview then shows "The engine keeps restarting this service", the application is exiting on its own, often because a variable it needs is missing. The lines under the alert and the service's Logs say why. The service keeps restarting goes through the usual causes.

Cloud runs no database migrations for you. If your project creates its tables with a command, open Terminal, pick web, and run it there.

8. Visit the generated address

At the first Done deployment, Cloud gives web an address on the platform's domain. Its Domains section shows the address moving through Waiting for DNS, Checking DNS and Preparing HTTPS to HTTPS active. Then Visit in the service's header opens it.

If Visit stays greyed out with "Add a domain to visit this service", the platform has no domain of its own configured. Go on to step 9.

9. Add your own domain

  1. Add the hostname

    On the service's Domains section, press Add domain. Keep Domain type on Your own domain, enter www.example.com as the Hostname, and press Add domain.

  2. Create the records

    Press Show DNS records on the new card. At your DNS provider, create the TXT record and each A or AAAA record it lists, copying names and values with the copy buttons. Keep the records DNS-only, with no proxy in front, until the domain is active.

  3. Wait for HTTPS active

    Cloud checks the records every five minutes, then waits for a certificate. The card reads HTTPS active when your domain answers over HTTPS. From then on, Visit opens your own domain first.

If the card reads DNS needs attention, correct the records and press Check again: Cloud does not check a failed domain again on its own. Domains covers every status.

10. Deploy on every push

From now on, a push to the branch deploys web again, with the trigger Git push. A push that arrives while a deployment is still running is dropped, not queued. Source and deploy triggers explains how to deploy only when you ask, or only when certain directories change.

Remove it again

Both services are charged every hour they run. To remove them, delete web first: on its Domains section remove each domain, then on Settings press Delete service and type its name. Then delete the database the same way. Deleting a database takes no backup, so download what you need first. Deleting is refused lists what else can stand in the way.