hasql: Fast PostgreSQL driver with a flexible mapping API

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Warnings:

Root of the "hasql" ecosystem. This library provides connection management, execution of queries and mapping of parameters and results. Extended functionality such as pooling, transactions and compile-time checking of SQL is provided by extension libraries. For more details and tutorials see the readme.

All error-reporting is explicit: database, protocol and connection failures are reported via the Either type instead of being thrown as exceptions.

The transport layer is pluggable via pqi, so "hasql" itself carries no C dependency. To compile an application you need to depend on "hasql" together with one adapter package and pass that adapter to Hasql.Connection.acquire as its first argument. Two adapters are available:


[Skip to Readme]

Properties

Versions 0.1.0, 0.1.1, 0.1.2, 0.1.3, 0.1.4, 0.1.5, 0.1.6, 0.2.0, 0.2.1, 0.2.2, 0.2.3, 0.3.0, 0.4.0, 0.4.1, 0.5.0, 0.6.0, 0.7.0, 0.7.1, 0.7.2, 0.7.3, 0.7.3.1, 0.7.3.2, 0.7.4, 0.14.0.2, 0.14.0.3, 0.15.0.2, 0.15.1, 0.15.1.1, 0.19.2, 0.19.3, 0.19.3.1, 0.19.3.2, 0.19.3.3, 0.19.4, 0.19.5, 0.19.6, 0.19.7, 0.19.8, 0.19.9, 0.19.10, 0.19.11, 0.19.12, 0.19.13, 0.19.14, 0.19.15, 0.19.15.1, 0.19.15.2, 0.19.16, 0.19.17, 0.19.17.1, 0.19.18, 0.19.18.1, 0.19.18.2, 0.20, 0.20.0.1, 0.20.1, 1, 1.1, 1.1.1, 1.2, 1.3, 1.3.0.1, 1.3.0.2, 1.3.0.3, 1.3.0.5, 1.3.0.6, 1.4, 1.4.0.1, 1.4.1, 1.4.2, 1.4.3, 1.4.4, 1.4.4.1, 1.4.4.2, 1.4.4.3, 1.4.5, 1.4.5.1, 1.4.5.2, 1.4.5.3, 1.5, 1.5.0.1, 1.5.0.2, 1.5.0.3, 1.5.0.4, 1.5.0.5, 1.5.1, 1.6, 1.6.0.1, 1.6.1, 1.6.1.1, 1.6.1.2, 1.6.1.3, 1.6.1.4, 1.6.2, 1.6.3, 1.6.3.1, 1.6.3.2, 1.6.3.3, 1.6.3.4, 1.6.4, 1.6.4.1, 1.6.4.2, 1.6.4.3, 1.6.4.4, 1.7, 1.7.0.1, 1.7.0.2, 1.8, 1.8.0.1, 1.8.0.2, 1.8.1, 1.8.1.1, 1.8.1.2, 1.8.1.3, 1.8.1.4, 1.9, 1.9.1, 1.9.1.1, 1.9.1.2, 1.9.2, 1.9.3, 1.9.3.1, 1.9.3.2, 1.10, 1.10.1, 1.10.2, 1.10.2.1, 1.10.2.2, 1.10.2.3, 1.10.2.4, 1.10.3, 1.10.3.1, 1.10.3.2, 1.10.3.3, 1.10.3.4, 1.10.3.5, 1.10.3.6, 1.10.3.7, 2.0.0.0, 2.0.0.1, 2.0.0.2, 2.0.0.3, 2.0.1.0, 2.1.0.0
Change log CHANGELOG.md
Dependencies aeson (>=2 && <3), attoparsec (>=0.10 && <0.15), base (>=4.14 && <5), base16-bytestring (>=1.0 && <1.1), bytestring (>=0.10 && <0.13), bytestring-strict-builder (>=0.4.5.4 && <0.5), comonad (>=5 && <5.1), contravariant (>=1.3 && <2), cryptohash-sha256 (>=0.11 && <0.12), dlist (>=0.8 && <0.9 || >=1 && <2), hashable (>=1.2 && <2), hasql, iproute (>=1.7 && <1.8), mtl (>=2 && <3), postgresql-binary (>=0.15 && <0.16), postgresql-connection-string (>=0.1 && <0.2), pqi (>=1.0 && <1.2), profunctors (>=5.1 && <6), scientific (>=0.3 && <0.4), text (>=1 && <3), text-builder (>=1 && <1.1), time (>=1.9 && <2), transformers (>=0.5 && <0.7), unordered-containers (>=0.2 && <0.3), uuid (>=1.3 && <2), vector (>=0.10 && <0.14), witherable (>=0.5 && <0.6) [details]
License MIT
Copyright (c) 2014, Nikita Volkov
Author Nikita Volkov <nikita.y.volkov@mail.ru>
Maintainer Nikita Volkov <nikita.y.volkov@mail.ru>
Category Hasql, Database, PostgreSQL
Home page https://github.com/nikita-volkov/hasql
Bug tracker https://github.com/nikita-volkov/hasql/issues
Source repo head: git clone https://github.com/nikita-volkov/hasql
Uploaded by NikitaVolkov at 2026-09-16T16:18:52Z

Modules

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for hasql-2.1.0.0

[back to package description]

Hasql

Hackage Continuous Haddock

PostgreSQL driver for Haskell, that prioritizes:

Hasql is production-ready and actively maintained. It's used by many companies and most notably by the Postgrest project. The API changes at major versions and each major release is supported for at least a year, as described under Support policy. Every change is recorded in the changelog.

Upgrading from 1.x? Hasql.Connection.acquire now takes a transport adapter as its first argument, so switching is a one-argument change, and the error types have been reshaped. The changelog lists every break.

Getting started

Hasql carries no C dependency. It programs against the "pqi" interface, and you pick the adapter that implements it. That means you depend on two packages, not one:

build-depends:
  hasql,
  pqi-ffi,  -- or pqi-native

Hasql.Connection.acquire then takes the adapter explicitly, as its first argument:

connection <- Hasql.Connection.acquire Pqi.Ffi.adapter settings

"pqi-ffi" is the stable, production-proven default. "pqi-native" is a pure-Haskell alpha with no C dependency at all. Transport adapters covers how to choose.

Example

Following is a complete application, which sums three numbers in Postgres by running one statement twice on the same connection.

{-# LANGUAGE OverloadedStrings #-}

import Data.Functor.Contravariant
import Data.Int
import Hasql.Session (Session)
import Prelude
import qualified Hasql.Connection as Connection
import qualified Hasql.Connection.Settings as Settings
import qualified Hasql.Decoders as Decoders
import qualified Hasql.Encoders as Encoders
import qualified Hasql.Session as Session
import qualified Hasql.Statement as Statement
import qualified Pqi.Ffi

main :: IO ()
main = do
  acquisition <- Connection.acquire Pqi.Ffi.adapter settings
  case acquisition of
    Left err -> fail (show err)
    Right connection -> do
      result <- Connection.use connection (sumSession 3 8 4)
      print result
  where
    settings =
      mconcat
        [ Settings.hostAndPort "localhost" 5432,
          Settings.user "postgres",
          Settings.password "postgres",
          Settings.dbname "postgres"
          -- Prepared statements are enabled by default.
          -- To disable them (e.g., for pgbouncer compatibility):
          -- Settings.noPreparedStatements True
        ]

-- | Session abstracts over the execution of operations on a connection.
-- It has a Monad instance, so statements compose.
sumSession :: Int64 -> Int64 -> Int64 -> Session Int64
sumSession a b c = do
  ab <- Session.statement (a, b) sumStatement
  Session.statement (ab, c) sumStatement

-- | Statement is a definition of an individual SQL-statement, accompanied by
-- a specification of how to encode its parameters and decode its result.
sumStatement :: Statement.Statement (Int64, Int64) Int64
sumStatement = Statement.preparable sql encoder decoder
  where
    sql =
      "select $1 + $2"
    encoder =
      mconcat
        [ fst >$< Encoders.param (Encoders.nonNullable Encoders.int8),
          snd >$< Encoders.param (Encoders.nonNullable Encoders.int8)
        ]
    decoder =
      Decoders.singleRow
        (Decoders.column (Decoders.nonNullable Decoders.int8))

Your First Statement is the same program with the annotations left in, explaining the encoder and decoder vocabulary line by line.

Errors

Every operation reports its failures as values. There are three error types, in Hasql.Errors, and which one you get tells you what state you're left in.

Hasql.Connection.acquire returns AcquireError, organized by the stage that failed: connecting, checking the server version, or initializing session settings.

Hasql.Connection.use returns UseError, which splits on the only distinction the caller can act on:

result <- Connection.use connection session
case result of
  Right a -> pure a
  -- The session failed, the connection is still live and reusable.
  Left (Errors.SessionUseError err) -> ...
  -- The connection is gone. Hasql has already closed it.
  Left (Errors.ConnectionUseError reason) -> ...

A ConnectionUseError means the handle is spent. Hasql finished the connection before returning, so every later use on it reports the same error and release is a no-op. Pools must discard it rather than return it. A SessionUseError carries a SessionError and leaves the connection untouched.

All three types implement IsError, which renders a message and details for logging and exposes the server's SQLSTATE through toSqlState where one was reported.

Documentation

The long-form material lives in hasql-docs.

The architecture reference is written to be consumed directly by coding agents as well as by people. Point an agent at the raw file and it has the whole system in context, with the rules numbered so they can be cited back in review.

Per-module API docs are on Hackage, and the continuous Haddock tracks master.

Ecosystem

Hasql is not just a single library, it is a granular ecosystem of composable libraries, each isolated to perform its own task and stay simple. Each one is separately versioned and separately owned, so a change in one doesn't ripple into the others and anyone can publish an alternative without asking. Instead of debating how transactions or cursors should be abstracted, the ecosystem carries competing answers side by side. Why Make It an Ecosystem? gives the full argument.

Want to list your package or correct something here? Make a PR.

Transport adapters

Unlike the extension libraries above, which are optional, a transport adapter is mandatory: Hasql needs one to talk to the server at all.

"pqi-native" is thoroughly tested: "pqi-conformance" runs it side by side with "libpq" on the same inputs and checks that the results agree, and the test-suites of "hasql", "hasql-pool" and "hasql-transaction" now run against both adapters, so the whole stack above the transport is exercised on it too. It's still labelled alpha, because it is not yet proven at production scale. That status lifts when it gets traction and successful usage reports.

The two adapters are fully interchangeable. Swapping between them is a one-argument change, nothing else, so you can try "pqi-native" today with no lock-in and fall back without a rewrite.

Discussions

Join GitHub Discussions to ask questions, provide feedback, suggest and vote on features, and help shape the future of Hasql.

Support policy

This policy is intended to balance stability for users with the ability to evolve the library.

Each major release of Hasql is supported for at least one year from the date of its first release. During this period, fixes are backported to the latest minor version of that major release.

After the support period ends, the release may continue to work but is no longer guaranteed to receive fixes.

You're welcome to post requests to change the policy or issues if you believe something is not being addressed.