Module 1 · Lesson 2

Adding a Database

Declare a Postgres dependency and wire it into your app.

What you'll learn
  • How requires declares resource dependencies
  • Shorthand vs expanded syntax for requires
  • How a declared database gets provisioned and wired in automatically
  • Passing provisioning hints like Postgres extensions with config
  • Adding a health check endpoint

The requires field

Most real apps need a database. Traditionally, you'd provision one manually, copy the connection string into an env var, and hope nobody forgets a step. With a Launchfile, you declare what you need and it's provisioned for you when you deploy.

The requires field declares: "My app needs this resource — provision it and give me connection details." The database creation, user setup, and credential injection are handled for you at deploy time.

Build it up

1
Start from where we left off in Lesson 1. Add requires: [postgres] — the shorthand syntax for declaring a database dependency.
version: launch/v1
name: my-app
runtime: node
commands:
  start: "node server.js"
requires: [postgres]
2
The shorthand is convenient, but expands to the full form behind the scenes. Both are valid.
requires: [postgres]

# is equivalent to:

requires:
  - type: postgres
3
Use set_env to wire the database connection into your app. $url resolves to the actual connection string at deploy time.
version: launch/v1
name: my-app
runtime: node
commands:
  start: "node server.js"
requires:
  - type: postgres
    set_env:
      DATABASE_URL: $url
4
Add a health check endpoint so your app's health can be verified after it starts. An HTTP GET /health is expected to return a 2xx response.
version: launch/v1
name: my-app
runtime: node
commands:
  start: "node server.js"
requires:
  - type: postgres
    set_env:
      DATABASE_URL: $url
health: /health
Shorthand
requires: [postgres]
Expanded
requires:
  - type: postgres

Provisioning hints with config

A requires entry also takes a config map, which passes provisioning hints straight to whatever provisions the resource — for Postgres, the one you'll reach for most is extensions, the list of Postgres extensions the database should have installed.

1
Declare the extensions your app needs under config. How — or whether — a provider honors them is provider-specific.
requires:
  - type: postgres
    config:
      extensions: [vector]
    set_env:
      DATABASE_URL: $url

The docker provider maps known package names to the SQL name CREATE EXTENSION expects (vector, not pgvector) and swaps in a Postgres image that ships it. The macos-dev provider does no such mapping — it drops your string straight into CREATE EXTENSION and, if that fails, continues silently, so an unrecognized name produces no error and no extension.

On docker, extensions are only created the first time a database's data directory initializes. Add config.extensions to an app that's already deployed, and the provider warns instead of applying it — naming the service and config.extensions, and pointing you to two remedies: run launchfile down --destroy then launchfile up to recreate the data (and the extensions) from scratch, or run the CREATE EXTENSION statements against the running database yourself to keep the data. See the spec's Resource configuration section for the full key list, and Lesson 8, Expressions & Resource Configuration, for naming, versioning, and config together.

How expressions work

Resource expressions

Inside set_env, you can reference properties of the provisioned resource using $ expressions:

  • $url — Full connection URL (e.g. postgres://user:pass@host:5432/dbname)
  • $host — Database hostname
  • $port — Port number
  • $user — Username
  • $password — Password
  • $name — Database name

These are expressions that resolve to real values at deploy time. Use $url when your framework expects a single connection string, or individual fields when it expects them separately.

Typos are easy to make and would otherwise resolve to an empty string — so launchfile validate warns when a property isn't in the standard vocabulary for the resource type (e.g. $hoost on postgres) and lists the properties that are. It's a warning, not an error: providers may expose extra properties beyond the standard set.

In the wild

Miniflux is a minimalist feed reader that needs Postgres. Notice how it uses set_env to wire the database, declares env vars with defaults, and even generates a secret for the admin password.

miniflux/LaunchfileView on GitHub
version: launch/v1
name: miniflux
description: "Minimalist and opinionated feed reader"
repository: https://github.com/miniflux/v2
logo: https://raw.githubusercontent.com/miniflux/v2/main/internal/ui/static/bin/icon-512.png

image: miniflux/miniflux:latest
provides:
  - name: web
    protocol: http
    port: 8080
    exposed: true
    tls: server-cert
requires:
  - type: postgres
    set_env:
      DATABASE_URL: $url
supports:
  # Miniflux switches the SAME listen address to TLS when both files are
  # supplied: internal/http/server/server.go:115 computes hasCertFiles and
  # :135-141 selects the TLS server. CERT_FILE, KEY_FILE and PORT are
  # configuration options (internal/config/options.go:121, :312, :519).
  - name: server-cert
    type: certificate
    set_env:
      PORT: "8080"
      CERT_FILE: $cert_file
      KEY_FILE: $key_file
env:
  RUN_MIGRATIONS:
    default: "1"
    description: "Run database migrations on startup"
  CREATE_ADMIN:
    default: "1"
    description: "Create admin user on first run"
  ADMIN_USERNAME:
    default: "admin"
    description: "Admin username"
  ADMIN_PASSWORD:
    required: true
    sensitive: true
    description: "Admin password"
    generator: secret
  BASE_URL:
    default: $app.url
    description: "Public-facing URL; miniflux uses it for absolute links and feed URLs"
health: /healthcheck
restart: always
requires:
Declares a Postgres dependency — provisioned automatically when the app deploys.
set_env:
Injects the connection URL into the DATABASE_URL environment variable.
generator: secret
Auto-generates a secure admin password at deploy time — no manual setup needed.
health: /healthcheck
This endpoint is checked to verify the app is alive.

Try it: npx launchfile up miniflux to launch this app locally.View in catalog

Check your understanding

What does requires: [postgres] declare?
Key takeaways
  • requires declares resource dependencies — they're provisioned automatically.
  • Use set_env with $url, $host, $port, etc. to wire connection details into your app.
  • Shorthand ([postgres]) and expanded syntax (- type: postgres) are equivalent.
  • config passes provider-specific provisioning hints, like Postgres extensions — how it's honored differs by provider.
  • Add health so your app's readiness can be verified after deployment.
esc
Type to search the docs