Hi!
I tend to use the following shell.nix
for my phoenix development.
The goal is to have each project run their own of everything so I run process locally and on domain socket only to avoid having to fiddle with different ports for different projects.
It is not completely automatic though. After the shell is installed you need to manually start postgres and create the postgres user needed for phoenix development.
Prerequisites:
Files needed
shell.nix:
with import <nixpkgs> {}; # This should probably be pinned to something. For me it points to 24.05 channel
let
basePackages = [
beam.packages.erlangR26.elixir_1_15
beam.packages.erlangR26.erlang
elixir_ls
inotify-tools
nodejs
yarn
postgresql
process-compose
];
PROJECT_ROOT = builtins.toString ./.;
hooks = ''
mkdir -p .nix-mix
mkdir -p .nix-hex
export MIX_HOME=${PROJECT_ROOT}/.nix-mix
export HEX_HOME=${PROJECT_ROOT}/.nix-hex
export PATH=$MIX_HOME/bin:$PATH
export PATH=$HEX_HOME/bin:$PATH
export LANG=en_NZ.UTF-8
export ERL_AFLAGS="-kernel shell_history enabled"
set -e
export PGDIR=${PROJECT_ROOT}/postgres
export PGHOST=$PGDIR
export PGDATA=$PGDIR/data
export PGLOG=$PGDIR/log
export DATABASE_URL="postgresql:///postgres?host=$PGDIR"
if test ! -d $PGDIR; then
mkdir $PGDIR
fi
if [ ! -d $PGDATA ]; then
echo 'Initializing postgresql database...'
initdb $PGDATA --auth=trust >/dev/null
fi
'';
in mkShell {
buildInputs = basePackages;
shellHook = hooks;
}
.envrc:
use nix
Initialize Shell
$ mkdir projects/thing
$ cd projects/thing
$ vim shell.nix # (with content from above)
$ vim .envrc # (with content from above)
$ direnv allow # Allow direnv to control the directory
Now direnv should make sure all the software and configuration in shell.nix
is installed.
Start postgres
Once installed I run postgres as my own user on domain sockets only:
$ cd project/thing
$ postgres -h '' -k $PGHOST # -h '' disables network to run on domain socket only, -k points to socket file directory
2024-08-20 14:43:57.679 NZST [2506190] LOG: starting PostgreSQL 15.7 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 13.2.0, 64-bit
2024-08-20 14:43:57.687 NZST [2506190] LOG: listening on Unix socket "/home/martink/projects/thing/postgres/.s.PGSQL.5432"
2024-08-20 14:43:57.707 NZST [2506193] LOG: database system was shut down at 2024-08-20 14:43:39 NZST
2024-08-20 14:43:57.717 NZST [2506190] LOG: database system is ready to accept connections
I tend to run postgres in the foreground so that I know what is happening. Usually I am using process-compose for this.
In another shell:
$ cd project/thing
$ createuser -d thing # create a postgres user with create database rights
Install and setup phoenix
Now the project is ready to install phoenix. Because of the MIX_HOME
and HEX_HOME
variables point to local directory we have an isolated environment
$ cd project/thing
$ mix archive.install hex phx_new
$ mix phx.new .
Modify the dev/config.exs
so the correct user is used and you connect to the correct socket:
config :thing, Thing.Repo,
username: "thing",
socket_dir: System.get_env("PGHOST"),
database: "thing_dev",
stacktrace: true,
show_sensitive_data_on_connection_error: true,
pool_size: 10
$ cd project/thing
$ mix ecto.create
$ iex -S mix phx.server
Hopefully now you should be able to have a fully self-container phoenix development environment.
I’ve tested this on NixOS 24.05