Creating Your First Project
This comprehensive tutorial will guide you through building a blog application with IHP. You’ll learn about database schemas, controllers, views, and relationships - all the fundamentals of IHP development.What You’ll Build
By the end of this tutorial, you’ll have:- A blog with posts (title, body, and timestamps)
- Markdown support for post content
- Comments on posts
- Full CRUD (Create, Read, Update, Delete) operations
- Form validation
- Beautiful URLs and routing
1. Project Setup
Create the Blog Project
First Time Setup: The first time you run this, it might take 10-15 minutes. Subsequent projects will be much faster as packages are cached.
Windows Users: Make sure you’re in the Linux part of the filesystem (not on
/mnt/), otherwise PostgreSQL will have issues.Start the Development Server
2. Database Schema
Design the Posts Table
Let’s create aposts table for our blog. Each post will have:
- An
id(UUID, automatically generated) - A
title(text) - A
body(text)
Open the Schema Designer
Navigate to http://localhost:8001/Tables
Create the Posts Table
- Right-click and select Add Table
- Enter
postsas the table name - Click Create Table
id column is automatically created with UUID type.Add the Title Column
- Right-click in the Columns pane
- Select Add Column
- Name:
title, Type:TEXT - Click Create Column
Understanding the Generated Code
IHP automatically generates Haskell types for your schema. View the generated code inbuild/Generated/Types.hs:
The Schema Designer is just a GUI for editing
Application/Schema.sql. You can always edit this file directly if you prefer.Verify the Schema
Check that the table was created:3. Generate the Controller
Use the Code Generator
In the Schema Designer, right-click on the
posts table and select Generate Controller.Alternatively, go to http://localhost:8001/Generators and click Controller.Preview and Generate
- Enter
Postsas the controller name - Click Preview to see what will be created
- Click Generate
View Your New Controller
Open http://localhost:8000/Posts to see the generated CRUD interface.
What Was Generated?
The generator created:Web/Types.hs - Action types:
Web/Controller/Posts.hs - Controller logic:
Web/View/Posts/ - View templates using HSX (JSX-like syntax):
4. Customize the Views
Create Your First Post
- Go to http://localhost:8000/Posts
- Click + New
- Enter:
- Title:
Hello World! - Body:
Lorem ipsum dolor sit amet, consetetur sadipscing elitr
- Title:
- Click Create Post
Improve the Show View
EditWeb/View/Posts/Show.hs:
Web/View/Posts/Show.hs
Make the Index View Clickable
EditWeb/View/Posts/Index.hs:
<th> tag.
5. Add Validation
Let’s ensure every post has a title. EditWeb/Controller/Posts.hs:
Web/Controller/Posts.hs
See all available validators in the API Documentation.
6. Add Timestamps
Add created_at Column
In the Schema Designer:
- Right-click on
poststable → Add Column to Table - Name:
created_at - Type:
TIMESTAMP - Default:
NOW() - Click Create Column
7. Add Markdown Support
Install the mmark Package
Editflake.nix and add mmark to haskellPackages:
flake.nix
Implement Markdown Rendering
EditWeb/View/Posts/Show.hs:
Web/View/Posts/Show.hs
Update the Form
Edit bothWeb/View/Posts/Edit.hs and Web/View/Posts/New.hs:
Add Markdown Validation
EditWeb/Controller/Posts.hs:
Web/Controller/Posts.hs
8. Add Comments
Create the Comments Table
Add Comments Table
In the Schema Designer:
- Right-click → Add Table
- Name:
comments - Add columns:
post_id(UUID) - Check “References posts”author(TEXT)body(TEXT)created_at(TIMESTAMP, default:NOW())
Configure Foreign Key
Click on “FOREIGN KEY: posts” next to
post_id to configure the ON DELETE behavior.Generate Comments Controller
- Go to Code Generator
- Controller name:
Comments - Click Preview → Generate
Link Comments to Posts
EditWeb/Types.hs to add postId parameter:
Web/Types.hs
Add “Add Comment” Link
EditWeb/View/Posts/Show.hs:
Update the New Comment Action
EditWeb/Controller/Comments.hs:
Web/Controller/Comments.hs
Update the Comment Form
EditWeb/View/Comments/New.hs:
Web/View/Comments/New.hs
Display Comments on Posts
EditWeb/View/Posts/Show.hs:
Web/View/Posts/Show.hs
Web/Controller/Posts.hs to fetch comments:
Web/Controller/Posts.hs
The
Include "comments" type tells IHP to fetch the related comments. The fetchRelated #comments function executes the query.Congratulations!
You’ve built a complete blog application with:- ✅ Posts with Markdown support
- ✅ Comments with relationships
- ✅ Form validation
- ✅ Timestamps and ordering
- ✅ Full CRUD operations
Next Steps
Star IHP on GitHub
Join the IHP community and contribute to the future of type-safe web development
Join IHP Slack
Get help with Haskell type errors and connect with other developers
Subscribe to Updates
Stay in the loop with IHP release emails
Explore the Guides
Learn about routing, views, controllers, forms, and more in The Basics section
Good to know: To delete an IHP project, just delete the project directory. All dependencies are managed by Nix, so there’s no system-wide cleanup needed.