Getting Started
Forge is a Go web framework that treats content as a first-class concept. Define a struct, wire a module, and Forge handles routing, templates, lifecycle enforcement, SEO metadata, and AI agent access — with zero third-party dependencies in core.
Installation
go get github.com/forge-cms/forge@latest
Your first content type
Every Forge content type embeds forge.Node:
type Post struct {
forge.Node
Title string `forge:"required,min=3"`
Body string `forge:"required"`
}
forge.Node provides UUID identity, a URL slug, and the full content lifecycle (Draft → Scheduled → Published → Archived). The lifecycle is always enforced — non-published content never appears on public endpoints.
Wiring the app
package main
import (
"database/sql"
"github.com/forge-cms/forge"
_ "modernc.org/sqlite"
)
func main() {
db, _ := sql.Open("sqlite", "./data/forge.db")
app := forge.New(forge.MustConfig(forge.Config{
BaseURL: "https://example.com",
Secret: []byte("...32 random bytes..."),
DB: db,
}))
app.Partials("templates/partials")
app.SEO(&forge.HeadAssets{
Preconnect: []string{"https://fonts.bunny.net"},
Stylesheets: []string{"/static/css/app.css"},
Favicons: []forge.FaviconLink{
{Rel: "icon", Type: "image/png", Sizes: "32x32", Href: "/static/favicon-32x32.png"},
},
})
app.Content(forge.NewModule((*Post)(nil),
forge.At("/posts"),
forge.Repo(forge.NewSQLRepo[*Post](db)),
forge.Templates("templates/posts"),
))
app.Run(":8080")
}
Forge registers five routes automatically: list, show, create, update, delete. Templates are parsed at startup — missing files cause a fast-fail error, not a runtime 404.
MustConfig validates your configuration at startup. Missing BaseURL or a Secret shorter than 16 bytes panics immediately — never at first request.
Shared partials
Put shared template fragments (nav, footer) in a directory and register them once:
app.Partials("templates/partials")
Every module template and custom handler template parsed via app.MustParseTemplate gets them automatically.
Head and SEO
Declare favicons, fonts, and stylesheets once in main.go via HeadAssets. Forge injects them into every page via {{template "forge:head" .}} — no per-template duplication:
app.SEO(
&forge.OGDefaults{
Image: forge.Image{URL: "https://example.com/og.png"},
TwitterSite: "@yourhandle",
},
&forge.HeadAssets{
Stylesheets: []string{"/static/app.css"},
Favicons: []forge.FaviconLink{{Rel: "icon", Href: "/favicon.ico"}},
},
)
Next steps
- [Content Types](/docs/content-types) — struct fields, validation, interfaces
- [Content Lifecycle](/docs/content-lifecycle) — draft, scheduled, published, archived
- [Templates and Head](/docs/templates-and-head) — forge:head, HeadAssets, PageHead, ContextFunc
- [AI Agents via MCP](/docs/mcp) — expose your content to AI agents