A small notes app: write a note, list them, delete them. Node and Express on the front, managed Postgres behind it.
The notes are the least interesting part. The point of this template is the wiring: how an app finds its database, keeps its schema in step, and reports health honestly.
- Finding the database. Nothing hardcodes a host. The managed Postgres bound to the app
arrives as
DATABASE_URL, and the same code runs locally against a container. - TLS the way velixir means it. The database encrypts every connection with a certificate
from velixir's own CA. node-postgres misreads
sslmode=requireas "verify against public CAs" and lets the URL override your options, so the stock setup fails withself-signed certificate.db.jsis the fix, and it is worth copying into your own apps. - A setup page instead of a crash. Start it with no database and it serves a page saying exactly what to do, rather than exiting. Lose the database later and it retries, explains the wait, and recovers on its own.
- An honest health check.
/healthzrunsSELECT 1. This app is useless without its database, so a failed query takes it out of rotation rather than serving errors. - Parameterised queries everywhere, and output escaped on the way to the browser.
Deploy it from the gallery. velixir creates a managed Postgres, binds it to the app as
DATABASE_URL, and holds the first deploy until the database is running, so the app starts
connected. The table is created on first boot.
By hand, for example after deploying your own copy with velixir deploy:
- Create a managed Postgres from the Databases page, or run
velixir db create. - Bind it to the app as
DATABASE_URL: on the database's page under Bound apps, orvelixir db bind <database-id> --app <app-id>. - Redeploy, with the Redeploy button on the live release in the Deploys tab.
npm install
DATABASE_URL=postgres://user:pass@localhost:5432/notes npm startThen open http://localhost:8080. With no sslmode in the URL, the connection is plain TCP,
which is what a local Postgres expects.
velixir deployMigrations run on boot. CREATE TABLE IF NOT EXISTS on startup is fine for one table
and one replica. Scale past one replica and several instances race the same migration on
every deploy. Move to a real migration step before that happens.
The certificate is not verified by default. The connection is encrypted, but db.js does not check
who issued the certificate, which matches what sslmode=require means everywhere else. To verify the
server as well, download your database's CA certificate from its page in the velixir dashboard
and connect with sslmode=verify-full and the ca option, which db.js leaves alone. See
https://velixir.net/docs/databases#verifying-the-server-certificate.
| Method | Path | Does |
|---|---|---|
GET |
/ |
The page |
GET |
/api/notes |
Newest 100 notes as JSON |
POST |
/api/notes |
Create one, {"body": "..."} |
GET |
/healthz |
200 when the database answers (or no database is bound yet), 503 while it is unreachable |
MIT.