# IHP: a Haskell and Nix web framework that trades setup cost for compile-time guarantees

> IHP is a batteries-included Haskell framework built on Nix, with type-safe routing, queries and HSX templates. Its pitch is longterm productivity; its price is a Nix-managed environment and a compiler that will reject code an AI wrote.

**digitallyinduced/ihp** — 🔥 The fastest way to build type safe web apps. IHP is a new batteries-included web framework optimized for longterm productivity and programmer happiness

- Repository: https://github.com/digitallyinduced/ihp
- Website: https://ihp.digitallyinduced.com/
- Stars: 5,349 · Forks: 227
- Language: Haskell
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/digitallyinduced-ihp

## What IHP is for, and who it is not for

IHP is a web framework written in Haskell, built on top of Nix, and licensed MIT. The README describes it as "batteries-included" and "optimized for longterm productivity and programmer happiness", and states it has been in production since 2017. That framing tells you the intended audience: teams that expect to keep an application alive for years and would rather pay at compile time than at 3am.

The specific problem it addresses is the usual one in a dynamically typed stack. A route that no controller handles, a query against a column that was renamed, a template that references a field the model no longer has: in IHP these are compile errors, not runtime 500s. The README lists type-safe routing, queries and HTML (HSX) as the first feature, and the code sample shows validation attached to a record before it is written.

Who it is not for matters just as much. If your team has no Haskell experience and no appetite to acquire it, the compiler becomes an adversary rather than a safety net. The framework's own AI section leans on this: the README says the type system "acts as a safety net" when AI generates code and the compiler verifies it. That argument only holds if someone on the team can read the type errors.

## How the pieces fit: controllers, HSX, and a monorepo of packages

The README shows the core loop. An action builds a new record, pipes it through `fill` to pull fields from the request, then `validateField` for each field, then `ifValid`. On the Left branch you re-render the form; on the Right branch you `createRecord` and `redirectTo` the index action. Validation and persistence are separate steps, so an invalid submission never reaches the database.

Views are written in HSX, which the README describes as "JSX-like HTML in Haskell". A render function takes a `Post` and returns `Html`, with `{post.title}` interpolated inside a `[hsx| ... |]` quasiquote. Because the argument is typed, a view that reads a field the model does not have fails to compile.

Around that core sits a monorepo. The README's package table lists `ihp` for routing, controllers, views, models and validation; `ihp-hsx` for templating; `ihp-ide` for the dev server, schema designer and code generators; `ihp-datasync` for real-time sync over WebSockets; `ihp-graphql`; `ihp-openai`; `ihp-ssc` for server-side components; `ihp-hspec` for tests; `ihp-migrate`; `ihp-mail`; `ihp-job-dashboard` for background job monitoring; and `ihp-pglistener` for PostgreSQL LISTEN/NOTIFY. That list is also the honest boundary of the framework: anything not on it is ordinary Haskell library work.

## Installing IHP and running a first action

The README's Quick Start is three lines. The first installs the project generator from nixpkgs, the second scaffolds an application, and the third starts the managed environment.

```bash
nix profile install nixpkgs#ihp-new
ihp-new myproject
cd myproject && devenv up
```

`devenv up` is where Nix earns its place. The README states that Nix handles all dependencies including PostgreSQL and GHC, that you do not need to learn Nix, and that every developer on the team gets the same environment. Expect the first run to spend a long time building or downloading that environment; subsequent starts are the point of the exercise.

Once the server is up, the README's sample controller is the smallest real thing to write. It creates a `Post`, fills `title` and `body` from the request, validates both as non-empty, and either re-renders `NewView` or persists and redirects.

```haskell
action CreatePostAction = do
    let post = newRecord @Post
    post
        |> fill @'["title", "body"]
        |> validateField #title nonEmpty
        |> validateField #body nonEmpty
        |> ifValid \case
            Left post -> render NewView { .. }
            Right post -> do
                post <- post |> createRecord
                redirectTo PostsAction
```

The view side is one function returning `Html`. The README gives this shape, and the compiler will complain if `post.title` is not a field on `Post`.

```haskell
renderPost :: Post -> Html
renderPost post = [hsx|
    <article>
        <h2>{post.title}</h2>
        <p>{post.body}</p>
    </article>
|]
```

Deployment is a separate tool rather than a container build. The README states that server configuration for nginx, TLS via Let's Encrypt, PostgreSQL and systemd services lives declaratively in your repository under `Config/nix/hosts/production/`, and that `deploy-to-nixos production` runs `nixos-rebuild` over SSH. It also states that systemd socket activation queues requests during deploys and that a watchdog recovers unresponsive processes.

```bash
deploy-to-nixos production
```

Docker and bare-metal deployments are mentioned as supported, with a link to the full deployment guide.

## Where IHP's approach costs you: Nix, hosting, and a narrow package list

The Nix-managed environment is the framework's biggest convenience and its biggest constraint, depending on who you are. The README is explicit that you do not need to learn Nix because IHP uses it behind the scenes. That is true until something breaks. When a dependency fails to build, the fix lives in Nix expressions, and the abstraction stops helping.

The deployment story has the same shape. `deploy-to-nixos` targets NixOS servers and runs `nixos-rebuild` over SSH. The README says Docker and bare-metal are also supported, but the detailed path it describes is the NixOS one. If your organization runs on a managed container platform and will not give you an SSH target running NixOS, you are off the documented road.

The package ecosystem is a monorepo, and that is a deliberate trade. Everything in the table is maintained together and versioned together, which removes dependency drift. It also means the framework's surface area is what the maintainers chose to build. Authentication, forms, validation, mail, background jobs, GraphQL and real-time sync are covered. Anything else is a Haskell library decision you make yourself, with the type-safety guarantees ending at that boundary.

One more honest limit: the README does not document rollback for `deploy-to-nixos`. It describes socket activation queueing requests during deploys and a watchdog recovering unresponsive processes, but how you return to a previous generation is not covered in the repository's top-level README, so treat that as something to confirm in the full deployment guide before you rely on it.

## IHP against Rails and Phoenix: same batteries, different bill

The closest comparison is Rails. Both are opinionated, both ship an ORM, migrations, mail, background jobs and generators, and both assume a single relational database. The difference is when errors surface. Rails resolves routes and column names at runtime, so a typo in a view is a 500 in production. IHP resolves them at compile time, so the same typo stops the build. Rails compensates with a far larger gem ecosystem and a much shorter path from zero to running code.

Phoenix is the nearer comparison on the real-time side. IHP's `ihp-datasync` provides real-time data sync over WebSockets, and the README advertises Auto Refresh as one line of code. Phoenix's channels are the established equivalent, and Elixir is generally considered a gentler first functional language than Haskell. If your team is choosing a functional stack from scratch, that is a real consideration, and the README offers no argument against it.

The deciding question is not which framework is better but which failure you would rather have. IHP moves failure earlier and makes it louder. Rails and Phoenix move failure later and make it cheaper to start. Neither is a defect; they are different bets about where your team's time is worth spending.

## Maintenance, upgrades, and what the MIT licence leaves you

The repository is not archived, and the last push was on 2026-09-15. The most recent release listed is v1.6.0 from 2026-06-21, preceded by v1.5.0 on 2026-03-25 and v1.4.1 on 2025-09-30. That is a steady cadence rather than a burst, and the version numbers suggest the project is past its early churn.

The upgrade cost is visible in the repository layout. There is a `UPGRADE.md` file at the top level and a `CHANGELOG.md`, which is where a breaking change would be recorded. The `Guide/` directory holds the documentation, and `Troubleshoot/` exists as a separate directory, which tells you the maintainers expect environment problems to be a recurring class of issue rather than an edge case. Because a project pins GHC, PostgreSQL and its dependencies through Nix, the practical upgrade path is to move the flake input and rebuild, then read `UPGRADE.md` for anything the compiler does not catch.

On licensing: IHP is MIT, which is permissive and places few obligations on what you build with it. That covers the framework itself. It says nothing about the licence of the PostgreSQL build, the GHC toolchain or any Haskell library you add, each of which carries its own terms. This is not legal advice; if your organization has a licence review process, the framework's MIT terms are the easy part and your dependency tree is the part worth checking.

## Conclusion

Adopt IHP if your team writes Haskell or is willing to, wants PostgreSQL and Nix pinned in one environment, and values compile-time rejection of bad routes and queries over a large third-party package ecosystem. Do not adopt it if you need Docker-first deployment with no Nix on the developer machine, or if you depend on libraries that only exist for Rails, Django or Phoenix. Before committing, verify three things: that devenv up brings up PostgreSQL and GHC on your hardware, that the packages you need exist in the monorepo list, and that deploy-to-nixos fits your hosting model. The repository was last pushed on 2026-09-15, and the latest release listed is v1.6.0 from 2026-06-21.

## FAQ

### Do I need to learn Nix to use IHP?

The README states that Nix handles all dependencies including PostgreSQL and GHC, and that you do not need to learn Nix because IHP uses it behind the scenes so that `devenv up` just works. In practice the abstraction holds until a dependency fails to build, at which point the fix is a Nix expression.

### What does IHP use for HTML templating?

HSX, provided by the `ihp-hsx` package. The README describes it as JSX-like HTML in Haskell and shows it used inside a `[hsx| ... |]` quasiquote in a function that returns `Html`, so field references in a template are checked by the compiler.

### How does IHP deploy an application to a server?

Through the built-in `deploy-to-nixos` tool, which runs `nixos-rebuild` over SSH against a NixOS server. The README states that nginx, TLS via Let's Encrypt, PostgreSQL and systemd services are configured declaratively in your repository under `Config/nix/hosts/production/`, and that Docker and bare-metal deployments are also supported.

### Which database does IHP work with?

PostgreSQL. The README lists PostgreSQL among the dependencies Nix manages, and the package table includes `ihp-pglistener` for PostgreSQL LISTEN/NOTIFY and `ihp-migrate` for database migrations. No other database is mentioned in the repository README.

## Sources

- [digitallyinduced/ihp on GitHub](https://github.com/digitallyinduced/ihp)
- [License: MIT](https://github.com/digitallyinduced/ihp/blob/master/LICENSE)
- [Project website](https://ihp.digitallyinduced.com/)
- [README](https://github.com/digitallyinduced/ihp/blob/master/README.md)
- [Releases](https://github.com/digitallyinduced/ihp/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/digitallyinduced-ihp
