Setup
Welcome to the Wonderful World of Skunk! This section will help you get everything set up.
Database Setup
In order to run the tutorial examples you will need a Postgres server with the world database loaded up, writable by the jimmy user, who must be able to log in with password banana. Our Docker image does exactly that.
docker run -p5432:5432 -d tpolecat/skunk-world
If you wish to use your own Postgres server you can download world/world.sql from the Skunk repository and load it up yourself.
Scala Setup
Create a new project with Skunk as a dependency.
libraryDependencies += "org.tpolecat" %% "skunk-core" % "0.6.4"
IDE Setup
For metals, no additional steps are needed.
For IntelliJ, add the skunk-intellij plugin to have correct code highlighting support for statements.
Verify Your Setup
Try out this minimal IOApp that connects to the database and selects the current date.
import cats.effect._
import skunk._
import skunk.implicits._
import skunk.codec.all._
import natchez.Trace.Implicits.noop // (1)
object Hello extends IOApp {
val session: Resource[IO, Session[IO]] =
Session.single( // (2)
host = "localhost",
port = 5432,
user = "jimmy",
database = "world",
password = Some("banana")
)
def run(args: List[String]): IO[ExitCode] =
session.use { s => // (3)
for {
d <- s.unique(sql"select current_date".query(date)) // (4)
_ <- IO.println(s"The current date is $d.")
} yield ExitCode.Success
}
}
Let's examine the code above.
- At ① we import the no-op
Tracer, which allows us to run Skunk programs with execution tracing disabled. We will revisit Tracing in a later section. - At ② we define a Resource that yields un-pooled Session values and ensures that they are closed after use. We specify the host, port, user, database, and password (see Session for information on ther connection options).
- At ③ we
usethe resource, specifying a block to execute during theSession's lifetime. No matter how the block terminates (success, failure, cancellation) theSessionwill be closed properly. - At ④ we use the sql interpolator to construct a
Querythat selects a single column of schema typedate(yieldingd, a value of typejava.time.LocalDate), then we ask the session to execute it, expecting a unique value back; i.e., exactly one row.
When we run the program we see the current date.
The current date is 2025-10-29.
Experiment
Here are some modifications that will cause runtime failures. Give them a try and see how Skunk responds.
- Try running with an invalid user, password, or database name.
- Introduce a typo into the SQL string.
- Change the decoder from
dateto another type liketimestamp.
We will see more examples later in the tutorial.