Documentation Index Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
Use this file to discover all available pages before exploring further.
In this tutorial, you’ll build a simple blog with pages, a layout, and styling. Server-rendered websites are great for content sites, blogs, and applications where SEO matters. The server generates complete HTML pages, which makes your site fast to load and easy for search engines to index.
Step 1: Create the Project
mizu new myblog --template web
cd myblog
go mod tidy
mizu dev
Open http://localhost:8080 to see the default page.
Step 2: Update the Layout
Edit views/layouts/main.html:
<! DOCTYPE html >
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title > {{.Title}} | My Blog </ title >
< link rel = "stylesheet" href = "/static/css/style.css" >
</ head >
< body >
< header >
< nav >
< a href = "/" class = "logo" > My Blog </ a >
< div class = "nav-links" >
< a href = "/" > Home </ a >
< a href = "/about" > About </ a >
</ div >
</ nav >
</ header >
< main >
{{template "content" .}}
</ main >
< footer >
< p > © 2024 My Blog </ p >
</ footer >
</ body >
</ html >
Step 3: Create a Blog Post Handler
Create handler/posts.go:
package handler
import " github.com/go-mizu/mizu "
type Post struct {
ID string
Title string
Summary string
Content string
Date string
}
var posts = [] Post {
{
ID : "1" ,
Title : "Getting Started with Mizu" ,
Summary : "Learn how to build web apps with Mizu" ,
Content : "Mizu is a lightweight web framework for Go..." ,
Date : "January 15, 2024" ,
},
{
ID : "2" ,
Title : "Building APIs" ,
Summary : "Create REST APIs quickly" ,
Content : "Building APIs with Mizu is straightforward..." ,
Date : "January 10, 2024" ,
},
}
func PostList () mizu . Handler {
return func ( c * mizu . Ctx ) error {
return c . Render ( "pages/posts" , map [ string ] any {
"Title" : "Blog Posts" ,
"Posts" : posts ,
})
}
}
func PostShow () mizu . Handler {
return func ( c * mizu . Ctx ) error {
id := c . Param ( "id" )
for _ , p := range posts {
if p . ID == id {
return c . Render ( "pages/post" , map [ string ] any {
"Title" : p . Title ,
"Post" : p ,
})
}
}
return c . Text ( 404 , "Post not found" )
}
}
Step 4: Create Post Views
Create views/pages/posts.html:
{{define "content"}}
< h1 > {{.Title}} </ h1 >
< div class = "posts" >
{{range .Posts}}
< article class = "post-card" >
< h2 >< a href = "/posts/{{.ID}}" > {{.Title}} </ a ></ h2 >
< p class = "date" > {{.Date}} </ p >
< p > {{.Summary}} </ p >
< a href = "/posts/{{.ID}}" class = "read-more" > Read more → </ a >
</ article >
{{end}}
</ div >
{{end}}
Create views/pages/post.html:
{{define "content"}}
< article class = "post" >
< header >
< h1 > {{.Post.Title}} </ h1 >
< p class = "date" > {{.Post.Date}} </ p >
</ header >
< div class = "content" >
< p > {{.Post.Content}} </ p >
</ div >
< footer >
< a href = "/" > ← Back to posts </ a >
</ footer >
</ article >
{{end}}
Step 5: Add Routes
Update app/web/routes.go:
package web
import " example.com/myblog/handler "
func ( a * App ) routes () {
a . app . Mount ( "/static/" , staticHandler ( a . cfg . Dev ))
// Pages
a . app . Get ( "/" , handler . PostList ())
a . app . Get ( "/posts/:id" , handler . PostShow ())
a . app . Get ( "/about" , handler . About ())
}
Step 6: Add Styling
Update assets/css/style.css:
* {
box-sizing : border-box ;
margin : 0 ;
padding : 0 ;
}
body {
font-family : -apple-system , BlinkMacSystemFont, 'Segoe UI' , Roboto, sans-serif ;
line-height : 1.6 ;
color : #333 ;
}
header {
background : #1a1a2e ;
padding : 1 rem 2 rem ;
}
nav {
display : flex ;
justify-content : space-between ;
align-items : center ;
max-width : 800 px ;
margin : 0 auto ;
}
.logo {
color : white ;
font-weight : bold ;
font-size : 1.5 rem ;
text-decoration : none ;
}
.nav-links a {
color : #ccc ;
text-decoration : none ;
margin-left : 1.5 rem ;
}
.nav-links a :hover {
color : white ;
}
main {
max-width : 800 px ;
margin : 2 rem auto ;
padding : 0 1 rem ;
}
.post-card {
background : #f9f9f9 ;
padding : 1.5 rem ;
margin-bottom : 1.5 rem ;
border-radius : 8 px ;
}
.post-card h2 a {
color : #1a1a2e ;
text-decoration : none ;
}
.date {
color : #666 ;
font-size : 0.9 rem ;
margin : 0.5 rem 0 ;
}
.read-more {
color : #4a90d9 ;
text-decoration : none ;
}
.post header {
margin-bottom : 2 rem ;
padding-bottom : 1 rem ;
border-bottom : 1 px solid #eee ;
}
footer {
margin-top : 3 rem ;
padding : 1 rem 0 ;
text-align : center ;
color : #666 ;
border-top : 1 px solid #eee ;
}
Step 7: Test It
Restart the server and browse:
http://localhost:8080/ - Post list
http://localhost:8080/posts/1 - Single post
http://localhost:8080/about - About page
What You Learned
Creating page handlers
Using templates with data
Layouts and partials
URL parameters in routes
Styling with CSS
Next Steps
Live Template Add real-time features
View Engine Learn more about templates