v1.2.0
IHP is a modern batteries-included haskell web framework, built on top of Haskell and Nix. Blazing fast, secure, easy to refactor and the best developer experience with everything you need - from prototype to production.
This release brings a new out of the box deployment process based on nixos-rebuild, a new way to get docker images for an IHP app and much more.
Major Changes
-
Deployment with
deploy-to-nixos
:
You can now easily deploy IHP apps to any NixOS server that is reachable via SSH. E.g. if you start a new AWS EC2 instance with an NixOS image and your SSH key, you can now deploy the IHP app, including database and migrations within minutes.The
flake.nix
can export a full NixOS configuration like this:{ inputs = { ihp.url = "github:digitallyinduced/ihp/v1.2"; nixpkgs.follows = "ihp/nixpkgs"; flake-parts.follows = "ihp/flake-parts"; devenv.follows = "ihp/devenv"; systems.follows = "ihp/systems"; }; outputs = inputs@{ ihp, flake-parts, systems, ... }: flake-parts.lib.mkFlake { inherit inputs; } { systems = import systems; imports = [ ihp.flakeModules.default ]; perSystem = { pkgs, ... }: { ihp = { enable = true; projectPath = ./.; packages = with pkgs; [ # Native dependencies, e.g. imagemagick nodejs ]; haskellPackages = p: with p; [ # Haskell dependencies go here p.ihp cabal-install base wai text hlint http-streams ihp-stripe ihp-oauth-google retry ]; }; }; flake.nixosConfigurations."staging.example.com" = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; specialArgs = inputs; modules = [ "${nixpkgs}/nixos/modules/virtualisation/amazon-image.nix" ihp.nixosModules.appWithPostgres ({ ... }: { security.acme.defaults.email = "[email protected]"; services.ihp = { domain = "myihpapp.com"; migrations = ./Application/Migration; schema = ./Application/Schema.sql; fixtures = ./Application/Fixtures.sql; sessionSecret = "xxx"; additionalEnvVars = { GHCRTS = "-A32M -N2"; }; }; # This should reflect the nixos version from the NixOS AMI initally installed # After the initial install, it should not be changed. Otherwise e.g. the postgres # server might need a manual data migration if NixOS changes the default postgres version system.stateVersion = "23.05"; # Optional Example: Email on App Crash systemd.services.app.onFailure = [ "notify-email@%n.service" ]; systemd.services.worker.onFailure = [ "notify-email@%n.service" ]; programs.msmtp = { enable = true; defaults = { tls = true; port = 587; }; accounts = { default = { auth = true; from = "[email protected]"; host = "email-smtp.eu-west-1.amazonaws.com"; user = "XXXXXXXX"; passwordeval = "echo 'XXXXXXXX'"; }; }; }; systemd.services."notify-email@" = { serviceConfig.Type = "oneshot"; path = with pkgs; [ systemd system-sendmail ]; scriptArgs = "%I"; script = '' UNIT=$(systemd-escape $1) TO="[email protected]" SUBJECT="$UNIT Failed" HEADERS="To:$TO\nSubject: $SUBJECT\n" BODY=$(systemctl status --no-pager $UNIT || true) echo -e "$HEADERS\n$BODY" | sendmail -t ''; }; # Optional Example: Run an IHP script every 30mins systemd.services.monitorCampaigns = { serviceConfig = { Type = "oneshot"; WorkingDirectory = "${ihpApp}/lib"; ExecStart = "${ihpApp}/bin/MonitorCampaigns"; }; environment = config.systemd.services.app.environment; onFailure = [ "notify-email@%n.service" ]; }; systemd.timers.monitorCampaignsEvery30Mins = { wantedBy = [ "timers.target" ]; partOf = [ "monitorCampaigns.service" ]; timerConfig = { OnCalendar = "*-*-* *:30:00"; Unit = "monitorCampaigns.service"; }; }; }) ]; }; }; }
Assuming your NixOS server can be conneted to via
ssh staging.example.com
, you can now run this:deploy-to-nixos staging.example.com
If you use an external postgres (this is likely the case for most serious production deployments), use
ihp.nixosModules.app
instead ofihp.nixosModules.appWithPostgres
.This will now apply the full above NixOS configuration to the server. Internally this tool is a wrapper around
nixos-rebuild
. E.g. the above call with result in:nixos-rebuild switch -j auto --use-substitutes --fast --flake .#staging.example.com --target-host staging.example.com --build-host staging.example.com --option substituters https://digitallyinduced.cachix.org --option trusted-public-keys digitallyinduced.cachix.org:digitallyinduced.cachix.org-1:y+wQvrnxQ+PdEsCt91rmvv39qRCYzEgGQaldK26hCKE= ssh staging.example.com systemctl start migrate
If you e.g. want to build the binaries on a different server than your runtime server, you can call
nixos-rebuild
directly instead of using thedeploy-to-nixos
wrapper.IHP now ships serveral NixOS modules that you can use to compose your IHP NixOS infrastructure.
-
Docker Images:
You can now build docker images from your IHP apps with ease:# Faster build times, but unoptimized GHC binaries nix build .#unoptimized-docker-image # Slow build times, but optimized GHC binaries nix build .#optimized-docker-image
-
Support HSX expressions like
<input value={project.id}/>
You can now use IHP UUIDs/ID values like user ID or project ID in HSX attributes:
-- Previous: <input value={inputValue project.id}/> -- New: <input value={project.id}/>
Minor Changes
- isActiveAction should take query string into account (https://github.com/digitallyinduced/ihp/pull/1725)
- Allow pure nix builds
- add make to devenv
- Guide on how to remove an uploaded image
- SSC do not encode nullary constructors to strings with the constructor tag
- Guide on how to test emails with Mailhog API
- Extracted env, envOrDefault and envOrNothing into it's own
IHP.EnvVar
module - Fixed missing retryJob implementation in IHP.Job.Dashboard
- Disabled ambiguous-fields warnings when loading IHP into ghci
- Add custom 403 response
- Added isValid function to check whether a record is valid quickly
- Fixed unhelpful error message when running migrations
- improved space handling in view generator
- Truncate identifiers for migration generator
- Fixed bug in Migration generator with a nested SELECT expression
- Fixed another bug in migration generator
- Add guide on conditional fill and security concerns
- Fixed DataSync sometimes not catching Websocket responses
- Escape postgres identifiers when using upper case
- Prefix AutoRefresh listener names with ar_ to avoid collision with DataSync listeners
- Removed duplicate HLS in IHP dev envs and removed unused stack binary
- Custom WebSocket Connection Options
- IHP OpenAI: Fixed
streamCompletionWithoutRetry
sometimes dropping tokens - Added non-streaming access to the OpenAI completion API via fetchCompletion
- Add back withHoogle support
- Add docs about GitHub Action
- Add Bounded to Enums
- Tailwind nixpkgs
- Bringing Test Suite sqlImport in line with IDE
- Use the Determinate Nix Installer on macOS
- Improve withTransaction docs
- Implement isEmpty for Data.Map
- Add Ord to Enums
- Allow empty select field for enums to force user selection
- Added .ghci for ihp-hsx
- Extracted ApplyAttribute class to IHP.HSX.Attribute
Full Changelog: v1.0.1...v1.1.0
Feature Voting
Help decide what's coming next to IHP by using the Feature Voting!
Updating
→ See the UPGRADE.md for upgrade instructions.
If you have any problems with updating, let us know on the IHP Discourse.
📧 To stay in the loop, subscribe to the IHP release emails (right at the bottom of the page). Or follow digitally induced on twitter.