Database
elements man database Read as markdownThe database is a core part of the Elements story. A web application is fundamentally a system for moving data between users and a database, and Elements treats the database accordingly. Migrations, real-time channels, cron, and background jobs are built into Elements directly on top of the database, not added as separate services. That deep integration is what makes building a web app quick.
The database is Postgres. Postgres, formally PostgreSQL, is an open-source relational database. Data is organized into tables with typed columns, and queries are written in SQL. Standardizing on a single database lets Elements deliver a consistent set of examples and packages that work for every project. Postgres is great for getting started and will scale with your application indefinitely.
Postgres Is Bundled
You do not install Postgres. Elements bundles Postgres 18.4 and manages it for you.
A per-machine background daemon (elements-machine) runs a single Postgres
cluster shared by every Elements project on the machine. The cluster is created
automatically on first use, kept healthy (self-healing), and configured for
loopback-only trust authentication. It listens on port 5433 (not the usual
5432), so it never collides with a Postgres you may already run. In development
its data directory is ~/elements/db.
On the first build, your project connects to the daemon, the cluster is ensured
ready, and two databases are created for the project automatically: the app
database and a test database. Their names derive from the project directory
name, normalized (for example MyApp becomes my_app and my_app_test), or
from database.name in config.jsoc.
There is nothing to start, nothing to install, and no connection string to paste. A freshly created app builds and runs with a working database out of the box.
Configure
The database block in config.jsoc supplies connection values. Every field is
optional; empty or omitted fields fall back to the bundled cluster defaults
(host 127.0.0.1, port 5433, user postgres, no password).
config.jsoc{ database: { name: "my_app", host: env("DB_HOST", "127.0.0.1"), port: env<number>("DB_PORT", 5433), user: env("DB_USER", "postgres"), password: env("DB_PASSWORD", ""), default: env("DB_DEFAULT", ""), ssl: env("DB_SSL", ""), sslRootCert: env("DB_SSL_ROOT_CERT", ""), }, }
config/env/development.envDB_HOST=localhost
A wrong-typed value fails the build before the project server tries to connect.
default is the database Elements connects to in order to create or drop the
app database. Neither statement can run over a connection to the database it
names, so an existing one is needed first. Blank means auto-detect: postgres,
then defaultdb. Set default, or the DB_DEFAULT variable the scaffolded
config reads, when your provider's bootstrap database has another name. See
Remote and Hosted Postgres.
ssl and sslRootCert set TLS for every connection to the database: the
build's migrations, elements db, the job server, and the app. The TLS section
below covers both.
To use a database other than the bundled cluster, a remote or hosted Postgres,
set DB_HOST (and the other DB_* values) to that server. When host points
somewhere other than the local cluster, Elements connects there and leaves the
bundled cluster out of the picture entirely. Several app servers share one
cluster this way, and every feature works across all of them. See
Remote and Hosted Postgres.
TLS
Every connection to the database uses the same TLS settings, so the build,
elements db, and the app connect the same way. With nothing set, Elements
picks by host: no TLS for the bundled cluster on loopback (127.0.0.1,
localhost, ::1), and an encrypted connection for every other host. A hosted
Postgres is encrypted with nothing configured.
To verify the server as well, give Elements your provider's CA certificate.
Save the file in the project, for example config/certs/db-ca.pem, and point
DB_SSL_ROOT_CERT at it in the environment's env file:
config/env/production.envDB_HOST=mydb.abc123.us-east-1.rds.amazonaws.com DB_SSL_ROOT_CERT=config/certs/db-ca.pem
The variable reaches the config through sslRootCert: env("DB_SSL_ROOT_CERT", "") in the database block shown above. With a CA file set, every connection
is verify-full: the server's certificate must chain to that CA and name the
host in DB_HOST. This is libpq's sslmode=verify-full, the setting HIPAA and
similar compliance reviews ask for. A relative path is relative to the project
root, so the certificate deploys with the project. Providers publish the file:
AWS RDS has its regional rds-ca bundles, DigitalOcean's control panel has a
CA certificate download, and Google Cloud SQL and Supabase offer the server CA
in their dashboards.
ssl (the DB_SSL variable in the scaffolded config) picks a mode by its libpq
name:
| Mode | Encrypted | Certificate checked |
|---|---|---|
disable |
no | no |
require |
yes | no, or the chain when a CA file is set (as in libpq) |
verify-ca |
yes | the chain, against the CA file this mode requires |
verify-full |
yes | the chain and the host name |
verify-full with no CA file checks against the trusted public CAs, which is
the right setting for a provider whose certificates are publicly trusted, such
as Neon. true and false also work, as require and disable.
A certificate that does not verify stops the build at its database step, with the host, the reason, and the setting to change, before any release goes live.
App and Test Databases
Elements provisions two databases per environment: an app database and a test database. The app database holds the application's data. Every build's tests run against the test database, leaving the app database untouched.
Tests automatically route to the test database. Route handlers, @rpc
functions, jobs, and cron all run against the app database. Elements picks
the right database based on the calling context, so there is no flag to flip per
query.
Tests are not a separate environment. They run as part of the build in every
environment (development, production, staging), against that environment's test
database. If you want a dedicated environment for pre-production verification,
configure a staging environment.
The default database names are <app> and <app>_test, derived from your
project name. Override the app database name under database.name in
config.jsoc; the test database always tracks <name>_test.
Elements maintains two schemas in every database. Application tables live on the
public schema. Elements-internal tables, including the migrations table and
the background jobs queue, live on a separate elements schema. This keeps
Elements' bookkeeping out of the way of your own tables and reuses Postgres's
own namespacing instead of inventing a prefix convention.