Deploy with a Database

This tutorial walks you through provisioning a managed PostgreSQL database on Temps, connecting it to your application, and deploying. No external database providers, no connection string juggling — Temps runs the database on your server and wires everything together automatically.


What you will build

By the end of this tutorial, you will have:

  • A managed PostgreSQL database running as a Docker container on your server
  • The database linked to your project with environment variables injected automatically
  • An application deployed and connected to the database
  • A Redis cache added as a bonus second service
  • Knowledge of how Temps manages per-environment database isolation

Time required: approximately 15 minutes.

What this tutorial covers and does not cover:

CoveredNot covered
Provisioning PostgreSQL and RedisMongoDB and S3 storage (same process, different service type)
Linking services to projectsDatabase migrations and schema management
Automatic environment variable injectionConnection pooling and performance tuning
Per-environment database isolationReplication and high availability
Querying data from the dashboardBackup and restore (previous tutorial)

Prerequisites

You need:

  • A running Temps instance with a deployed project (complete Your First Deployment first)
  • An application that uses a database — any framework that reads a database connection string from an environment variable will work. This tutorial shows examples for Next.js, Express, and generic Node.js.

If your current project does not use a database, that is fine. You can still follow along to provision the service and link it — then add database code later.


Create a PostgreSQL service

A managed service in Temps is a Docker container that Temps provisions, monitors, and backs up for you. You create the service once and then link it to any number of projects.

  1. In the sidebar, click Services
  2. Click Create Service
  3. Select PostgreSQL as the service type
  4. Configure it:
  • Name
    Name
    Description

    A unique name for this service, e.g. my-app-db. This becomes part of the Docker container name (postgres-my-app-db) and the volume name.

  • Name
    Parameters
    Description

    Temps auto-fills sensible defaults. You can adjust:

    • Port — The host port to bind. Auto-assigned starting from 5432. Bound to 127.0.0.1 only (not publicly accessible).
    • Docker Image — Default: gotempsh/postgres-walg:18-bookworm (PostgreSQL 18 with WAL-G for streaming backups). You can also use timescale/timescaledb-ha:pg18 if you need TimescaleDB.
    • Max Connections — Default: 100. Increase for high-concurrency applications.

    Fields that are auto-generated and read-only after creation:

    • Databasepostgres (the root database; per-project databases are created automatically when linked)
    • Usernamepostgres
    • Password — A random 16-character alphanumeric string, encrypted at rest

Click Create. Temps pulls the Docker image (if not cached), creates a container and a persistent volume, starts the service, and waits for the health check (pg_isready) to pass.

When the status shows Running, your database is ready.


Creating a service does not automatically connect it to any project. You need to explicitly link them.

  1. Open your project in the dashboard
  2. Click Services in the project sidebar
  3. Click Link Service
  4. Select the PostgreSQL service you just created
  5. Click Link

That is it. The next time your project deploys, Temps will inject the database connection details as environment variables into your application container.

What linking does under the hood

When you link a PostgreSQL service to a project, Temps:

  1. Creates a dedicated database inside the PostgreSQL instance named {project_slug}_{environment_slug} (e.g. my_app_production). Each project-environment combination gets its own isolated database.
  2. Generates environment variables with the connection details, using the Docker container name as the hostname (so containers can talk to each other over the Docker network).
  3. Stores the link in a project_services table — only one service of each type can be linked per project.

Understand the injected environment variables

When a PostgreSQL service is linked to your project, Temps injects these environment variables at deploy time:

  • Name
    POSTGRES_URL
    Description

    The full connection string: postgres://postgres:PASSWORD@postgres-SERVICE-NAME:5432/PROJECT_ENV_DB

    This is the variable most frameworks expect. The hostname is the Docker container name (e.g. postgres-my-app-db), the port is always 5432 (the internal port, not the host-mapped port), and the database name is your project-environment combination.

  • Name
    POSTGRES_HOST
    Description

    The container hostname: postgres-my-app-db

  • Name
    POSTGRES_PORT
    Description

    The internal port: 5432

  • Name
    POSTGRES_NAME
    Description

    The root database name: postgres

  • Name
    POSTGRES_DATABASE
    Description

    The per-project database name: my_app_production

  • Name
    POSTGRES_USER
    Description

    The username: postgres

  • Name
    POSTGRES_PASSWORD
    Description

    The auto-generated password.

Preview before deploying

To see exactly which variables will be injected without deploying:

  1. Go to your project's Services page
  2. Click on the linked PostgreSQL service
  3. Click Preview Environment to see all variable names and masked values

Common framework mappings

Most frameworks expect DATABASE_URL rather than POSTGRES_URL. You have two options:

Option A: Add an alias environment variable (recommended)

In your project's Environment Variables page, add:

KeyValue
DATABASE_URL$POSTGRES_URL

Temps supports variable interpolation — $POSTGRES_URL expands to the actual connection string at deploy time.

Option B: Update your application code

Read from POSTGRES_URL instead of DATABASE_URL:

// Before
const db = new Pool({ connectionString: process.env.DATABASE_URL });

// After
const db = new Pool({ connectionString: process.env.POSTGRES_URL });

Update your application

Add database access to your application. Below are examples for common frameworks. The key point: read the connection string from POSTGRES_URL (or DATABASE_URL if you set up the alias).

Connect to PostgreSQL

// db/index.ts
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';

const pool = new Pool({
  connectionString: process.env.POSTGRES_URL,
});

export const db = drizzle(pool);

Add a health check that verifies database connectivity

A good health endpoint confirms the database is reachable:

api/health/route.ts (Next.js App Router)

import { Pool } from 'pg';
import { NextResponse } from 'next/server';

const pool = new Pool({
  connectionString: process.env.POSTGRES_URL,
});

export async function GET() {
  try {
    await pool.query('SELECT 1');
    return NextResponse.json({ status: 'ok', database: 'connected' });
  } catch (error) {
    return NextResponse.json(
      { status: 'error', database: 'disconnected' },
      { status: 500 }
    );
  }
}

This gives your uptime monitor a way to detect database outages, not just application crashes.


Deploy and verify

Commit your changes and push:

git add .
git commit -m "feat: add PostgreSQL database connection"
git push

Temps detects the push, builds your application, and deploys it. This time, the deploy includes the database environment variables.

Verify the connection

After the deployment completes:

  1. Visit your application's health endpoint (e.g. https://my-app.yourdomain.com/health or /api/health)
  2. Confirm you see "database": "connected" in the response
  3. In the Temps dashboard, go to your project's Services page — the linked service should show the environment variables that were injected

Troubleshooting

If your application fails to connect to the database:

  • Name
    Connection refused
    Description

    Your app is trying to connect to localhost instead of the container name. Make sure you are reading POSTGRES_URL (which uses the Docker container hostname) rather than hardcoding localhost.

  • Name
    Database does not exist
    Description

    Temps creates the per-project database on first deploy. If you linked the service after the last deploy, trigger a new deployment (push a commit or use the Redeploy button).

  • Name
    Authentication failed
    Description

    The password in POSTGRES_URL is auto-generated. Do not set the password manually in your environment variables — let Temps inject it.

  • Name
    Timeout connecting
    Description

    Check that the PostgreSQL service is running. Go to Services in the sidebar and verify the status is Running. If it is stopped, click Start.


Explore your data

Temps includes a built-in data explorer that lets you query your databases directly from the dashboard without installing any tools.

  1. Open your project in the dashboard
  2. Click Services in the project sidebar
  3. Click on your linked PostgreSQL service
  4. Use the Query tab to run SQL
-- See all tables
SELECT tablename FROM pg_tables WHERE schemaname = 'public';

-- Check your data
SELECT * FROM users LIMIT 10;

-- Database size
SELECT pg_size_pretty(pg_database_size(current_database()));

This is useful for quick debugging and data inspection. For ongoing database management, connect with your preferred client (pgAdmin, DBeaver, TablePlus) using the host port shown on the service details page:

# Connect from your local machine (requires SSH tunnel or direct access)
psql "postgres://postgres:PASSWORD@your-server-ip:PORT/my_app_production"

Add Redis for caching

The process for adding any managed service is the same. Here is how to add Redis:

  1. Go to Services in the sidebar
  2. Click Create Service
  3. Select Redis
  4. Give it a name, e.g. my-app-cache
  5. Click Create — Temps starts a Redis container (gotempsh/redis-walg:8-bookworm)

Link it to your project:

  1. Open your project's Services page
  2. Click Link Service, select the Redis service
  3. Click Link

On next deploy, these additional environment variables are injected:

  • Name
    REDIS_URL
    Description

    Full connection string: redis://:PASSWORD@redis-my-app-cache:6379/DB_NUMBER

  • Name
    REDIS_HOST
    Description

    Container hostname: redis-my-app-cache

  • Name
    REDIS_PORT
    Description

    Internal port: 6379

  • Name
    REDIS_PASSWORD
    Description

    Auto-generated password.

  • Name
    REDIS_DATABASE
    Description

    A database number (0-15) assigned per project, derived from a hash of the project and environment slugs.

Use Redis in your application:

lib/redis.ts

import { createClient } from 'redis';

export const redis = createClient({
  url: process.env.REDIS_URL,
});

redis.connect();

Push and deploy. Your application now has both a database and a cache, managed entirely by Temps.


What you have accomplished

You now have a complete data stack running on your server:

ServiceContainerPurpose
PostgreSQLpostgres-my-app-dbPrimary database with per-environment isolation
Redisredis-my-app-cacheCaching and session storage

Key concepts you learned:

  • Services are shared: One PostgreSQL instance can serve multiple projects, each getting its own database
  • Environment isolation: Temps creates {project}_{environment} databases automatically, so production and staging data never mix
  • Automatic wiring: Link a service to a project and Temps handles the environment variables, networking, and database creation
  • Docker networking: Containers communicate using Docker container names as hostnames over an internal network. The database port is only exposed to 127.0.0.1 on the host.

Available service types

The same workflow applies to all managed services:

ServiceDefault ImageEnvironment Variables
PostgreSQLgotempsh/postgres-walg:18-bookwormPOSTGRES_URL, POSTGRES_HOST, POSTGRES_PORT, POSTGRES_DATABASE, POSTGRES_USER, POSTGRES_PASSWORD
Redisgotempsh/redis-walg:8-bookwormREDIS_URL, REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_DATABASE
MongoDBgotempsh/mongodb-walg:8.0MONGODB_URL, MONGODB_HOST, MONGODB_PORT, MONGODB_DATABASE, MONGODB_USERNAME, MONGODB_PASSWORD
S3 Storagerustfs/rustfs:1.0.0-alpha.78S3_BUCKET, S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY

What to explore next

Was this page helpful?