Releases: digitallyinduced/ihp
v1.4.1
v1.4.0
Highlights
- 🚀 Improved Dev Server: faster, more reliable reloads without race conditions.
- 📦 Ecosystem split: IHP now modular (
ihp-ide,ihp-ssc,ihp-migrate,ihp-sitemap). - 🔧 New helpers:
createRecordDiscardResult,copyRecord,queryUnionList,orderByAscJoinedTable. - 🛠️ Production-ready: warp + systemd integration, healthcheck endpoint, better job runner handling.
- 🐘 Compiler upgrade: GHC 9.8 (with support for 9.10 and 9.12).
Major Changes
- Added
createRecordDiscardResult(complementsupdateRecordDiscardResult) for cases where the result is not needed (e.g. scheduling jobs). - Added
copyRecordfor easier duplication of database records. - Improved Dev Server reliability and performance. Race conditions on rapid file updates are fixed by using proper bracketed resource management.
- Split IHP into multiple packages (
ihp-ide,ihp-ssc,ihp-migrate,ihp-sitemap) for cleaner dependency boundaries. - Production improvements: integrated
warp-systemd, added healthcheck endpoint, and improved socket activation. - Upgraded to GHC 9.8, with support for 9.10.x and 9.12.x.
Minor Changes
Nix / Deployment
- Added options:
rtsFlags,optimizationLevel,appName. - Support for aarch64 NixOS deployments.
- Faster
nix buildvia caching ofGenerated.Types. - Simplified migration service (
IHP_MIGRATION_DIR). - Dropped dependency on
ihpsource to reduce closure size. - Updated nixpkgs to 25.05 and devenv to 1.8.2.
- Use flake overlays instead of manual
mkGhcCompiler. - Don’t set
system.stateVersionautomatically (configured in project’sflake.nix).
Job Runner
- Jobs with timeouts are now restarted if workers crash.
- Improved async handling of jobrunner.
- Use
ResourceTfor job worker scheduling to avoid leaks. - Exceptions are now printed to logs for easier debugging.
- Don’t log job worker SQL queries.
DataSync
- Fixes: arrays double-escaped, connections closed prematurely, crash with spaces in table names, non-snake_case column names.
- Features: added
useCount, customnewRecordBehaviour, support for event triggers, React 18useSyncExternalStore. - Avoid creating
large_pg_notificationstable when not needed.
HSX / View Layer
- Added
uncheckedHsxandcustomHsx. - Lucid2 port and core library split.
- Added missing HTML attributes.
- Fixed generator issues (brackets, variable references, migrations).
- Use Blaze helpers in HSX.
SQL / Query Layer
- Added
filterWhereInCaseInsensitive,queryUnionList,orderByAscJoinedTable/orderByDescJoinedTable. - Refactored pagination queries.
- Logging improvements: show final SQL, rounded runtimes, simplified log format with icons.
Storage
- Support custom storage directory via
IHP_STORAGE_DIR. - Support custom filenames in
storeFileFromPath. - S3
storagePrefixnow returns base URL. - Fix
createTemporaryDownloadUrlFromPath.
Miscellaneous
- Support custom base URL in
assetPath. - Add
withPGListener. - Always evaluate Blaze HTML.
- Added
mainInParentDirectory. - Enabled warp file cache in production.
- Set default gracefulShutdownTimeout.
- Improved schema compiler performance.
IHP OpenAI
- Removed deprecated
promptfield. - Added support for tools and tool calls,
response_format, Anthropiccache_control, Google Gemini. - Added
extraHeaders,finish_reason,usagein streaming responses. - Changed
maxTokens,temperature,presencePenalty,frequencyPenaltytoMaybe. - Improved error messages and quota exceeded feedback.
- Added
reasoningEffortand [parallelToolCalls](9e3c3983bd3942311ea23e...
v1.3.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 many small quality of life improvements to IHP, fixes lots of bugs and comes with several helpful documentation improvements. There's been over 190 commits since v1.2.0
Major Changes
-
New CLI command:
new-session-secret:
Until now it's always been a bit tricky to get a new secret for theIHP_SESSION_SECRETenv var. To fix that we've added a newnew-section-secretcommand. Run it from the command line inside your IHP project, and it will generate a new random key to use for theIHP_SESSION_SECRETenv var:$ new-session-secret 1J8jtRW331a0IbHBCHmsFNoesQUNFnuHqY8cB5927KsoV5sYmiq3DMmvsYk5S7EDma9YhqZLZWeTFu2pGOxMT2F/5PnifW/5ffwJjZvZcJh9MKPh3Ez9fmPEyxZBDxVp
-
Proper support for non
idprimary keys:
Previously IHP assumed that your tables primary keys are calledid, and that you don't use composite primary keys.With this release the following SQL schema will compile without any errors:
CREATE TABLE bits ( bit_arbitrary_ident UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL ); CREATE TABLE parts ( part_arbitrary_ident UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL ); CREATE TABLE bit_part_refs ( bit_ref UUID NOT NULL, part_ref UUID NOT NULL, PRIMARY KEY(bit_ref, part_ref) );
-
GHC Upgrade: 9.4 -> 9.8.2
-
New Function:
sqlQuerySingleRow:
Runs a raw sql query, that is expected to return a single result row
Like 'sqlQuery', but useful when you expect only a single row as the resultdo user <- sqlQuerySingleRow "SELECT id, firstname, lastname FROM users WHERE id = ?" (Only userId)
-
New Function:
sqlExecDiscardResult:
Runs a sql statement (like aCREATEstatement), but doesn't return any resultsqlExecDiscardResult "CREATE TABLE users ()" ()
There's now also
updateRecordDiscardResult, which is likeupdateRecord, but doesn't return the updated record. -
Worker support exponential backoff:
instance Job DraftEmailJob where backoffStrategy = ExponentialBackoff { delayInSeconds = 30 } perform job = do -- ...
Minor Changes
- DataSync: Configurable message timeout
- HSX: Allow attributes sse-connect and sse-swap
- Allow a submit button to be disabled
- Use a more robust check for
isUrlvalidator validateMaybe: Helper to allowvalidateFieldto work on Maybe valuesfileOrNothingshould check fileContent isn't empty- Add debounce to fsnotify
- Form: Add
urlField - ihp-new: Remove cachix install step
- Remove HLS config initialization
- nix: Extracted out duplicate binary cache config
- Fixed base64 error when deploying with deploy-to-nixos
- Fixed migrate service failing to build when the IHP app has no migrations yet
- nix: Fixed some postgres settings in appWithPostgres nixos config
- Disable nix sandbox for deploy-to-nixos: This makes it work better out of the box with projects that use npm
- ihp-new: Create git repo to avoid issues when IHP is part of a larger git repo
- Allow optimized builds with deploy-to-nixos
- deploy-to-nixos: Fixed db init script
- Use built-in ping pong mechanism of the latest version of websockets
- Fixed npm install when running an IHP app on latest nixpkgs
- deploy-to-nixos: Fixed database being used before it has been created
- deploy-to-nixos: Switch to the right user before creating tables
- Remove unused datePickers code
- Allow easier SMTP config envs
- Add loadSchema service
- Worker: Write to log instead of using putStrLn
- Worker: Fixed poller not scheduling concurrent jobs
- Allow sql dumping via the Makefile
- Fixed Underscore in ID column leads to compile error in code generation
- Fix SchemaCompiler to support non-id-pks
- Made request logger less verbose by not logging requests to static files: This was the existing behaviour until we switched out the static middleware a while ago
- make it easier to spot schema + fixture errors
- Only track exception (e.g. with sentry) in production: This was the expected behaviour, but turns out I missed one place
- ihp-openai: Don't use deprecated prompt anymore, as we mostly use the chat API
- ihp-openai: Added missing assistantMessage
- Simplify session vault key handling: Moved the session vault key from the ApplicationContext and RequestContext data structure to a global variable. This is the suggested way by the WAI developers.
- Allow overriding the logger in the controller context
- fixed long constraint names cause verbose patches in migrations
- Pin devenv to a stable release
- Document creation of Docker with Nix and Podman
Docs
- Show example how to send a link from Mail
- Update tailwindcss instructions
- Improvements to the emacs documentation (you're better off with vim)
- Add docs about Unique Constraints
- Docs about Passing JSON to the View
Full Changelog: v1.2.0...v1.3.0
Updating
→ See the UPGRADE.md for upgrade instructions.
If you have any problems with updating, [let us know on the IHP Discourse](https://discuss.ihp....
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.nixcan 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.appinstead 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 migrateIf you e.g. want to build the binaries on a different server than your runtime server, you can call
nixos-rebuilddirectly instead of using thedeploy-to-nixoswrapper.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](5e3b561569ae28dc85106ed97...
v1.1.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 some large improvements to the dev environment by integrating devenv.sh, adds native GPT4 support through ihp-openai and much more.
Major Changes
-
devenv.sh x IHP:
IHP projects now use devenv.sh. devenv is a wrapper around nix flakes that provides fast, declarative, reproducable and composable development environments. It supercedes the previous.envrcapproach. Especially projects with lots of dependencies are much faster to open with devenv. -
ihp-openai:
The newihp-openaipackage adds an easy way to integrate GPT3 and GPT4 to your Haskell web apps. The library is extracted from a production app at digitally induced. Compared to existing haskell libs this library is a streaming API (so works great with IHP AutoRefresh and IHP DataSync), works with the latest Chat API, and has smart retry on error without throwing away tokens. Also it's battle tested in real world production use cases.The package can be found in the IHP repo and a demo project can be found on GitHub as well.
Example:
module Web.Controller.Questions where import Web.Controller.Prelude import Web.View.Questions.Index import Web.View.Questions.New import Web.View.Questions.Edit import Web.View.Questions.Show import qualified IHP.OpenAI as GPT instance Controller QuestionsController where action QuestionsAction = autoRefresh do questions <- query @Question |> orderByDesc #createdAt |> fetch render IndexView { .. } action NewQuestionAction = do let question = newRecord |> set #question "What makes haskell so great?" render NewView { .. } action CreateQuestionAction = do let question = newRecord @Question question |> fill @'["question"] |> validateField #question nonEmpty |> ifValid \case Left question -> render NewView { .. } Right question -> do question <- question |> createRecord setSuccessMessage "Question created" fillAnswer question redirectTo QuestionsAction action DeleteQuestionAction { questionId } = do question <- fetch questionId deleteRecord question setSuccessMessage "Question deleted" redirectTo QuestionsAction fillAnswer :: (?modelContext :: ModelContext) => Question -> IO (Async ()) fillAnswer question = do -- Put your OpenAI secret key below: let secretKey = "sk-XXXXXXXX" -- This should be done with an IHP job worker instead of async async do GPT.streamCompletion secretKey (buildCompletionRequest question) (clearAnswer question) (appendToken question) pure () buildCompletionRequest :: Question -> GPT.CompletionRequest buildCompletionRequest Question { question } = -- Here you can adjust the parameters of the request GPT.newCompletionRequest { GPT.maxTokens = 512 , GPT.prompt = [trimming| Question: ${question} Answer: |] } -- | Sets the answer field back to an empty string clearAnswer :: (?modelContext :: ModelContext) => Question -> IO () clearAnswer question = do sqlExec "UPDATE questions SET answer = '' WHERE id = ?" (Only question.id) pure () -- | Stores a couple of newly received characters to the database appendToken :: (?modelContext :: ModelContext) => Question -> Text -> IO () appendToken question token = do sqlExec "UPDATE questions SET answer = answer || ? WHERE id = ?" (token, question.id) pure ()
Bildschirmaufnahme.2023-04-17.um.23.48.41.mov
-
onlyWhere,onlyWhereReferencesandonlyWhereReferencesMaybe:
In IHP code bases you often write filter functions such as these:getUserPosts user posts = filter (\p -> p.userId == user.id) posts
This can be written in a shorter way using
onlyWhere:getUserPosts user posts = posts |> onlyWhere #userId user.id
Because the
userIdfield is an Id, we can useonlyWhereReferencesto make it even shorter:getUserPosts user posts = posts |> onlyWhereReferences #userId user
If the Id field is nullable, we need to use
onlyWhereReferencesMaybe:getUserTasks user tasks = tasks |> onlyWhereReferences #optionalUserId user
-
GHC 9.2.4 -> 9.4.4
We've moved to a newer GHC version 👍 -
Initalizers
You can now run code on the start up of your IHP app using an initializer. For that you can calladdInitializerfrom your project'sConfig.hs.The following example will print a hello world message on startup:
config = do addInitializer (putStrLn "Hello World!")
This is especially useful when using IHP's Row level security helpers. If your app is calling
ensureAuthenticatedRoleExistsfrom theFrontController, you can now move that to the app startup to reduce latency of your application:config :: ConfigBuilder config = do -- ... addInitializer Role.ensureAuthenticatedRoleExists
-
Multiple Record Forms
You can now use
nestedFormForto make nested forms with the IHP form helpers. This helps solve more complex form use cases.Here's a code example:
renderForm :: Include "tags" Task -> Html renderForm task = formFor task [hsx| {textField #description} <fieldset> <legend>Tags</legend> {nestedFormFor #tags renderTagForm} </fieldset> <button type="button" class="btn btn-light" data-prototype={prototypeFor #tags (newRecord @Tag)} onclick="this.insertAdjacentHTML('beforebegin', this.dataset.prototype)">Add Tag</button> {submitButton} |] renderTagForm :: (?formContext :: FormContext Tag) => Html renderTagForm = [hsx| {(textField #name) { disableLabel = True, placeholder = "Tag name" } } |]
-
Faster Initial Startup for large IHP Apps:
TheGenerated.Typesmodule is a module generated by IHP based on your project'sSchema.sql. The module is now splitted into multiple sub modules, one for each table in yourSchema.sql. This makes the initial startup of your app faster, as the individual sub modules can now be loaded in parallel by the compiler. -
Static Files Changes:
IHP is now using the more actively maintainedwai-app-staticinstead ofwai-middleware-staticfor serving files from thestatic/directory.The old
wai-middleware-statichad some issues, particular related to leaking file handles. Alsowai-app-statichas better cache handling for our dev mode.You might see some changes related to caching of your app's static files:
- files in
static/vendor/previously had more aggressive caching rules, this is not supported anymore. - files in dev mode are now cached with
maxage=0instead ofCache-Control: nocache - application assets are now cached forever. As long as you're using IHP's
asssetPathhelper, this will not cause any issues.
Additionally the routing priority has changed to save some syscall overhead for every request:
Previously:
GET /test.txt Does file exists static/test.txt? => If yes: return file => If no: run IHP router to check for an action matching /test.txtNow:
GET /test.txt Run IHP router to check for an action matching /test.txt Is there an action matching this? => If yes: Run IHP action => If no: Try to serve file static/test.txt? - files in
-
.envFiles:
Next to the.envrc, you can now save secrets outside your project repository by putting them into the.envfile.
The.envis not committed to the repo, so all secrets are safe against being accidentally leaked. -
HSX Comments:
You can now write Haskell comments inside HSX expressions:render MyView { .. } = [hsx| <div> {- This is a comment and will not render to the output -} </div> |]
-
HSX Doctype:
HTML Doctypes are now supported in HSX. Previously you had to write them by using the underlying blaze-html library:render MyView { .. } = [hsx| <!DOCTYPE html> <html lang="en"> <body> hello </body> </html> |]
Minor Changes
- Fixed Google OAuth docs use outdated google JS library
- [added interval type to parser an...
v1.0.1
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.
A new IHP release, containing mostly bug fixes and small improvements to existing features. There's no major new feature in this release 🛠️
Minor Changes
- Serverside Components: fix update class attribute of input or textarea elements
- Support Postgres Arrays in DataSync
- Normalized Null handling in DataSync: This fixes a bug where queries like 'col = NULL' is generated instead of the correct 'col IS NULL'
- DataSync: Fixed whereIn
- Fixed null handling in DataSync 'field IN (null)' queries
- Fixed table deletion causing bad DROP POLICY statement
- Fixed race condition in build of scripts
- Fixed DataSync's opimistic deleteRecord operation not correctly undone when the operation fails on the server
- fix, ssc createNode operatin bug, when target node (by path) is a text node by @leobm
- Adding string instance to EnvVarReader useful for FilePath type in logger. by @Montmorency
- fix zsh config in ihp-new
- Fixed 'ENABLE ROW LEVEL SECURITY' statement for a table with spaces in it's name breaks the SQL
- Fixed problem with calling crypto.randomUUID on older browsers
- hsx: Allow { ...values} spread, with a space in front
- fix comment css sourcemap
- Fixed updateRecord calls in DataSync failing when the patch size is more than 8000 bytes
- Fixed DataSync crashing when an UPDATE query is executed that doesn't change any values
- Log exceptions in main loop of PGListener
- Fixed onPing callback never called: This caused AutoRefresh sessions to be accidentally garbage collected, even when they're still alive
- Added support for 'CREATE UNLOGGED TABLE' syntax in sql files
Notable Documentation Changes
- Lot's of typos and small issues have been fixed by @agreif
- IHP Cloud Deployment documentation has been removed
- Shipnix Deployment documentation has been added by @kodeFant
- Improvments to Emacs docs by @unhammer
- Various fixes by @rvarun11
Full Changelog: v1.0.0...v1.0.1
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 forum.
📧 To stay in the loop, subscribe to the IHP release emails (right at the bottom of the page). Or follow digitally induced on twitter.
v1.0.0
Two years after the first public release of IHP I’m very happy and proud to announce the release of version 1.0! 🎉
→ Read the full release announcement on the IHP Website.
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.
Major Changes
-
🎨 Bootstrap 5:
We've finally upgraded from Bootstrap 4 to Bootstrap 5 🎉
E.g. all forms rendered withformFornow expect you're using bootstrap 5 by default. Bootstrap 4 is still supported and available if needed, e.g. if you don't want to update your application. -
💻 M1 Builds:
Thanks to a new mac mini sponsored by MacStadium, we now have prebuilt binaries for Apple M1 devices. Previously it could take up multiple hours to compile everything needed for IHP from scratch. Now this just takes a minute of downloading binaries.
-
🗂️ Schema Designer: Index Management
The IHP Schema Designer now supports creating, editing and deleting column indexes from the GUI. Previously this was only possible by editing theSchema.sqlmanually:
-
🐎 Smaller & Faster Production Builds
We've optimized the nix build process. Previously when building for production, the output of the nix build process contained many dev tools, like the Postgres server and Haskell Language Server. These are not needed in production. With the recent changes they're excluded from the production build. This saves tons of space. E.g. when packaging a simple IHP app, the file size of the docker image moved from 300MB -> 80MB.The build process now uses all available cores when calling
make. This will speed up builds that rely on many IHP Scripts.
Other Changes
- Removed github discussions from help popover
- Fixed darkmode design of help popover
- Run :l Main automatically when opening ghci
- Added callstacks to exceptions thrown during config
- added deepseq constraint on Enum so that paramList works as expected.
- Add hs-brolti and wai-middleware-brotli nix config
- Add hs-brotli wai-middleware-brotli To build
- Updated ihp-hsx package definitions
- Enabled split sections for app
- Fixed dev server start fails when build/ihp-lib points to a non existing directory
- Use
record.fieldsyntax instead ofget #field recordin docs - Added docs on dot notation
- Removed outdated note on unsupported syntax in HSX
- currentAdmin, currentAdminOrNothing, currentAdminId, ensureIsAdmin now works without explicit type passed
- Added generic currentRoleOrNothing
- Fixed haddock build
- Tried adding failing test for https://github.com/digitallyinduced/ihp/issues/1451
- Improve error report when when parsing the Schema.sql fails
- Added note on contributing docs
- Use dot notation in ModelSupport
- Make editor docs more visible
- Updated links to mailing list
- Improved support for preEscapedTextValue
- Refactored ConvertibleStrings instance to use ApplyAttribute instance
- adding some docs on using scripts from ghci
- added testConfig example for script with different logging level
- switch appConfig to testConfig for consistency
- Made a specific example for importing Config and running it from ghci
- Added ParPat and working on ConPat so that generic lambda pattern matching works in HSX
- More of the expression type checking still need to find map to
[HsType]forTH.Conp - Trying to map constructors to types for template haskell
- Now working with simple constructor pattern matching (no type annotation) no infix constructors yet.
- Implementation of Exact rdrName allows for use of infix operators in HSX!
- Infix and pattern matching on constructors working. Added tests. No type annotations in Constructor patterns supported.
- Allow formFor with GET method
- Use Queue for ghci output
- Extracted and refactored FileWatcher
- Refactored handling of toolserver
- Refactored state handling of live reload notification server
- Fixed rename table operation doesn't correctly rename other DDL statements
- Fixed running a broken migration causes a bad error message
- Replace ConfigProvider and LoggingProvider with dot notation
- make Welcome page page more responsible
- When dropping a column, also drop related policies
- Fixed user_id quick col has a ihp_user_id() default value, even when RLS is not used
- Fixed race condition in dev server that causes reload to not work
- Exported currentRole functions
- Disabled split-sections
Full Changelog: v0.20.0...v1.0.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 IH...
v1.0-RC2
This is the second release candidate for the soon-to-be-published IHP v1.0. See #1501
See v1.0.0-rc1 for a list of all changes. This release contains small bug fixes only.
Other Changes
v1.0-RC1
This is a release candidate for the soon-to-be-published IHP v1.0. See #1501
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.
Major Changes
-
🎨 Bootstrap 5:
We've finally upgraded from Bootstrap 4 to Bootstrap 5 🎉
E.g. all forms rendered withformFornow expect you're using bootstrap 5 by default. Bootstrap 4 is still supported and available if needed, e.g. if you don't want to update your application. -
💻 M1 Builds:
Thanks to a new mac mini sponsored by MacStadium, we now have prebuilt binaries for Apple M1 devices. Previously it could take up multiple hours to compile everything needed for IHP from scratch. Now this just takes a minute of downloading binaries.
-
🗂️ Schema Designer: Index Management
The IHP Schema Designer now supports creating, editing and deleting column indexes from the GUI. Previously this was only possible by editing theSchema.sqlmanually:
-
🐎 Smaller & Faster Production Builds
We've optimized the nix build process. Previously when building for production, the output of the nix build process contained many dev tools, like the Postgres server and Haskell Language Server. These are not needed in production. With the recent changes they're excluded from the production build. This saves tons of space. E.g. when packaging a simple IHP app, the file size of the docker image moved from 300MB -> 80MB.The build process now uses all available cores when calling
make. This will speed up builds that rely on many IHP Scripts.
Other Changes
- Removed github discussions from help popover
- Fixed darkmode design of help popover
- Run :l Main automatically when opening ghci
- Added callstacks to exceptions thrown during config
- added deepseq constraint on Enum so that paramList works as expected.
- Add hs-brolti and wai-middleware-brotli nix config
- Add hs-brotli wai-middleware-brotli To build
- Updated ihp-hsx package definitions
- Enabled split sections for app
- Fixed dev server start fails when build/ihp-lib points to a non existing directory
- Use
record.fieldsyntax instead ofget #field recordin docs - Added docs on dot notation
- Removed outdated note on unsupported syntax in HSX
- currentAdmin, currentAdminOrNothing, currentAdminId, ensureIsAdmin now works without explicit type passed
- Added generic currentRoleOrNothing
- Fixed haddock build
- Tried adding failing test for https://github.com/digitallyinduced/ihp/issues/1451
- Improve error report when when parsing the Schema.sql fails
- Added note on contributing docs
- Use dot notation in ModelSupport
- Make editor docs more visible
- Updated links to mailing list
- Improved support for preEscapedTextValue
- Refactored ConvertibleStrings instance to use ApplyAttribute instance
- adding some docs on using scripts from ghci
- added testConfig example for script with different logging level
- switch appConfig to testConfig for consistency
- Made a specific example for importing Config and running it from ghci
- Added ParPat and working on ConPat so that generic lambda pattern matching works in HSX
- More of the expression type checking still need to find map to
[HsType]forTH.Conp - Trying to map constructors to types for template haskell
- Now working with simple constructor pattern matching (no type annotation) no infix constructors yet.
- Implementation of Exact rdrName allows for use of infix operators in HSX!
- Infix and pattern matching on constructors working. Added tests. No type annotations in Constructor patterns supported.
- Allow formFor with GET method
- Use Queue for ghci output
- Extracted and refactored FileWatcher
- Refactored handling of toolserver
- Refactored state handling of live reload notification server
- Fixed rename table operation doesn't correctly rename other DDL statements
- Fixed running a broken migration causes a bad error message
- Replace ConfigProvider and LoggingProvider with dot notation
- make Welcome page page more responsible
- When dropping a column, also drop related policies
- Fixed user_id quick col has a ihp_user_id() default value, even when RLS is not used
Full Changelog: v0.20.0...v1.0.0-rc1
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 forum.
📧 To stay in the loop, subscribe to the IHP release emails (right at the bottom of the page). Or follow digitally induced on twitter.
v0.20.0
A new IHP release, containing bug fixes and productivity improvements to existing features 🛠️
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.
Major Changes
-
⚪ Dot Notation:
IHP goes OOP-ish. Thanks to a compiler update in this release we can now make use of dot notation à lasomeThing.someAttribute🎉-- Previously: get #title project -- Now: project.title
This also works in HSX:
[hsx| <!-- Previously: --> <div>{get #title project}</div> <!-- Now: --> <div>{project.title}</div> |]This can especially be useful when you're dealing with nested records, e.g. when working with
fetchRelated:[hsx| <!-- Previously: --> <div>{get #name (get #userId project)}</div> <!-- Now: --> <div>{project.userId.name}</div> |] -
🛠️ HSX Improvements:
We've refactored HSX to fix some of the common issues, like HSX not support expressions likeallEnumValues @MyEnum. This refactoring was needed to make dot notation work in HSX as well.[hsx| <!-- Previously failed because of the @ symbol: --> {allEnumValues @Color} <!-- Just works with IHP 0.20: --> {allEnumValues @Color} |] -
➕ New Function: isActiveAction
ReturnsTruewhen the given action matches the path of the currently executed action[hsx| {isActiveAction PostsAction} |] -
🌎 I18n Routing:
As we're preparing I18n support for IHP apps, we've already refactored the routing to support langauge prefixes, e.g./de/for a german site and/en/for english.Here's an advanced code example of this in action:
instance FrontController WebApplication where ... -- the previous code assigning controllers is still required router additionalControllers = do mlocale <- optional do string "/" string "en" let router = defaultRouter additionalControllers case mlocale of Just locale -> case locale of "en" -> putContextRouter EN_UK router _ -> IHP.RouterPrelude.error "This should be unreachable" Nothing -> router
Once IHP has full i18n, you can find more on this in the documentation.
-
🤖 GHC 9.2.4:
We've updated to a new major version of GHC. Previously IHP apps were using GHC 8.10.7. This improves support for M1/M2 macs and allows for dot notation.
Other Changes
- Add Guide On Using Compression Middleware.
- normalize newlines in sql functions before diffing for migration
- Fixed unique constraint with multiple columns showing up as unmigrated changes
- Use "$out/lib" as the default working directory for binaries produced with nix
- fixed design of reference checkbox in new column view
- Extracted column rename logic from Schema Designer action into Schema Operations
- Fixed table renames not updating references indexes
- use font-display swap for inter
- Splitted Lockable.isLocked into an IO and a pure function
- Run migration sql commands in a single database statement: The stateful way of doing the transaction could potentially use a different database connection from the pool. This change avoids that issue.
- HSX: Support underscores in data attribute names
- Removed outdated nix install instructions for macOS
- Fixed SchemaCompiler crashing on Set and Select statements
- diffAppDatabase should work with the configured database url instead of the hardcoded dev db
- Enabled split-sections for IHP builds for smaller binaries on linux
- Normalize spaces in sql functions
- Added failing test for parsing table names starting with public
- Fixed schema parser not correctly parsing table names starting with public
- Use 'CREATE OR REPLACE' when updating a function in a migration
- Fixed update operations in DataSync operation not removing database records from a subscription when the WHERE condition doesn't match anymore
- Fixed broken rendering of reference checkbox
- Adapted reference checkbox to new layout
- Reference Checkboxes no longer have the same id (fixes clickability)
- Add slot parameter for custom elements
- Fixes qualified identifiers in policies causing a diff in the migrations: A policy in the form
CREATE POLICY a ON t USING t.f = public.fcontains a qualified sub-expressiont.f. When dumping this policy from pg_dump we get a unqualifiedf = public.fcondition instead. So we need to normalize the Policy to the normal formCREATE POLICY a ON t USING f = public.f - Added missing sql keyword ALL to list of protected keywords
- fixed favicon missing
- Fixed race-condition in closing of DataSync subscription
- Improved error message when DeleteDataSubscription fails because the DataSubscription doesn't exists
- Allow mounting websocket apps that have a HTTP fallback
- Extracted DataSync message handler
- Fixed migration generator fails with a IN (..) expression in a policy
- Fixed job runners running with 2 concurrency even when it's limited to max concurrency 1
Full Changelog: v0.19.0...v0.20.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 forum.
📧 To stay in the loop, subscribe to the IHP release emails (right at the bottom of the page). Or follow digitally induced on twitter.





