**NOTE:** all of these methods may be obsoleted, when `ensure*` is
reworked, but it is expected that they will stay viable for running
database migrations.
**NOTE:** please make sure that any added migrations are idempotent (re-runnable).
#### in database's setup `postStart` {#module-services-postgres-initializing-extra-permissions-superuser-post-start}
`ensureUsers` is run in `postgresql-setup`, so this is where `postStart` must be added to:
```nix
{
systemd.services.postgresql-setup.postStart = ''
psql service1 -c 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO "extraUser1"'
psql service1 -c 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO "extraUser1"'
# ....
'';
}
```
#### in intermediate oneshot service {#module-services-postgres-initializing-extra-permissions-superuser-oneshot}
Make sure to run this service after `postgresql.target`, not `postgresql.service`.
They differ in two aspects:
- `postgresql.target` includes `postgresql-setup`, so users managed via `ensureUsers` are already created.
- `postgresql.target` will wait until PostgreSQL is in read-write mode after restoring from backup, while `postgresql.service` will already be ready when PostgreSQL is still recovering in read-only mode.
Both can lead to unexpected errors either during initial database creation or restore, when using `postgresql.service`.
```nix
{
systemd.services."migrate-service1-db1" = {
serviceConfig.Type = "oneshot";
requiredBy = "service1.service";
before = "service1.service";
after = "postgresql.target";
serviceConfig.User = "postgres";
environment.PGPORT = toString services.postgresql.settings.port;
path = [ postgresql ];
script = ''
psql service1 -c 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO "extraUser1"'
psql service1 -c 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO "extraUser1"'
# ....
'';
};
}
```
## Authentication {#module-services-postgres-authentication}
Local connections are made through unix sockets by default and support [peer authentication](https://www.postgresql.org/docs/current/auth-peer.html).
This allows system users to login with database roles of the same name.
For example, the `postgres` system user is allowed to login with the database role `postgres`.
System users and database roles might not always match.
In this case, to allow access for a service, you can create a [user name map](https://www.postgresql.org/docs/current/auth-username-maps.html) between system roles and an existing database role.
### User Mapping {#module-services-postgres-authentication-user-mapping}
Assume that your app creates a role `admin` and you want the `root` user to be able to login with it.
You can then use [](#opt-services.postgresql.identMap) to define the map and [](#opt-services.postgresql.authentication) to enable it:
```nix
{
services.postgresql = {
identMap = ''
admin root admin
'';
authentication = ''
local all admin peer map=admin
'';
};
}
```
::: {.warning}
To avoid conflicts with other modules, you should never apply a map to `all` roles.
Because PostgreSQL will stop on the first matching line in `pg_hba.conf`, a line matching all roles would lock out other services.
Each module should only manage user maps for the database roles that belong to this module.
Best practice is to name the map after the database role it manages to avoid name conflicts.
:::
## Upgrading {#module-services-postgres-upgrading}
::: {.note}
The steps below demonstrate how to upgrade from an older version to `pkgs.postgresql_13`.
These instructions are also applicable to other versions.
:::
Major PostgreSQL upgrades require a downtime and a few imperative steps to be called. This is the case because
each major version has some internal changes in the databases' state. Because of that,
NixOS places the state into {file}`/var/lib/postgresql/<version>` where each `version`
can be obtained like this:
```
$ nix-instantiate --eval -A postgresql_13.psqlSchema