A Datastar Go web frontend framework
90
stars
638
commits
Go
primary language
Sep 13, 2026
updated
[!WARNING] Alpha Software: Datapages is still in early development. APIs are subject to change and you may encounter bugs.
[!NOTE] v0.10 is coming with API improvements, stateful pages, service worker support, multi-app modules and more!
A Templ + Go + Datastar web framework for building dynamic, server-rendered web applications in pure Go.
Focus on your business logic, generate the boilerplate Datapages parses your app source package and generates all the wiring. Routing, sessions and authentication, SSE streams, CSRF protection, type-safe URL and action helpers, Prometheus metrics - so your application code stays clean and takes full advantage of Go's strong static typing and high performance.
No matter whether you're building real-time collaborative dynamic web app or simple HTMX-style websites - Datapages will serve you well.
counter — Real-time counter built twice in one module,
bare bones as app/simple and polished as app/fancy. Bare bones starting
point, and the example of a module that builds more than one application.todolist — Real-time collaborative todo list with per-tab
server-side state (Most Tao conform example).calculator — Hybrid calculator app that runs both as
a multi-client server and single-client Desktop app.classifieds —
Full-featured classifieds marketplace with sessions, auth, Prometheus metrics,
Grafana dashboards and load testing.tailwindcss —
Minimal static page demonstrating Tailwind CSS integration.webcomponents —
Landing page with vanilla and Lit-based Web Components
bundled via esbuild through a custom watcher.sqlitesessions —
Custom sessions.Manager implementation backed by SQLite
via sqinn-go (no cgo).go install github.com/romshark/datapages/cmd/datapages@latest
datapages init
| Command | Description |
|---|---|
datapages init | Initialize a new project with scaffolding and configuration. |
datapages gen | Parse the app model and generate the datapages package. |
datapages watch | Start the live-reloading development server. |
datapages lint | Validate the app model without generating code. |
datapages version | Print CLI version information. |
Nothing about the build is configured. Every setting is read from the code that already states it.
Static file serving is turned on by an embed.FS whose doc comment names the
URL path it is served at, the way a page names its route. The comment gives
the prefix, the //go:embed directive gives the directory:
// app/assets.go
// StaticFS is /static/
//go:embed static/*
var StaticFS embed.FS
The URL path in the comment must start and end with / and cannot be /.
The //go:embed directive must name exactly one directory inside the app
package.
The browsable argument of datapages.WithAssets lists a directory that has
no index.html. Pass browsable=false in production to avoid exposing every
embedded file.
The app package, the session data type, the metrics mode and the package to
generate into are the type arguments of the datapages.NewServer call.
s, err := datapages.NewServer[
app.App, // App
datapages.DisableSessions, // SessionData
datapages.DisablePrometheus, // Metrics
datapagesgen.Server, // S
](
a, broker, datapages.WithLogger(logger),
)
App names the app package. Metrics decides the Prometheus counters:
datapages.EnablePrometheus generates the code that counts and requires
WithPrometheus to serve it, datapages.DisablePrometheus generates no
counters, has no Prometheus imports and rejects that option. Use
datapages init --prometheus=false to scaffold a project whose entry point
names it.
S must name that app package's datapagesgen, which is where its code is
generated:
app/datapagesgen for ./app, app/frontend/datapagesgen for ./app/frontend.
One module may build any number of applications. Each app package gets its own model, its own generated package and its own entry point:
app/frontend/ cmd/frontend/
app/frontend/datapagesgen/
app/admindashboard/ cmd/admindashboard/
app/admindashboard/datapagesgen/
Events are the one thing the applications of a module share: two of them given
one broker publish into one namespace. No two of them may claim the same subject,
which datapages gen and datapages lint check over the whole module.
To let two applications receive each other's events, declare the event once in
a package both import and use that type in both, instead of declaring it twice.
datapages gen generates every one of them. datapages watch runs one, so a
module that builds more than one needs --app to say which:
datapages watch --app frontend
A module with no NewServer call yet is generated into app/datapagesgen
from ./app and gets a cmd/server/main.go written for it.
What is left is the tooling, which datapages.yaml or datapages.yml in the
module root carries. If both files exist, the CLI treats that as an error.
cmd: cmd/server
watch:
exclude:
- ".git/**" # git internals
- ".*" # hidden files/directories
- "*~" # editor backup files
These top-level keys are supported:
cmd: where datapages gen writes the first cmd/server/main.go,datapages watch builds while no NewServer call is written in a
main package yet. Default: cmd/server. Once such a call exists,
the command it is written in is the entry point and this key is unused,
which is why a module building several applications does not set it.
Must be a relative path inside the module:
an absolute path or a .. segment is rejected.watch: optional development server settings (app host, proxy timeout,
debounce, TLS, compiler flags, logging, custom watchers, etc.)See SPECIFICATION.md for the full source package specification, including handler signatures, parameters, return values, events, sessions, and modules.
See FAQ.md for frequently asked questions.
Datapages ships pluggable modules with swappable implementations:
Manager[Data]
Broker
TokenWriter, TokenValidator
Tokens - the built-in default: HKDF-SHA256 over the session token, BREACH-resistant masking, nothing to configureTokenGeneratorThe reason I built Datapages is that the combination of Datastar + Go + Templ is my preferred way of writing server-centric web applications. But in every project I used this tech stack for I kept repeating the same code patterns and solving the same problems over and over again. I realized many developers are repeating the same patterns too and struggle with the common pitfalls:
Your Datastar frontends are your rocket to extraterrestrial worlds of the internet. The further you want to go, the heavier a rocket you'll require. Hence, you need powerful boosters to get it off the ground and overcome Earth's gravity. Such boosters exist in the form of awesome templates like zangster300/northstar, which will quickly get your rocket to the stratosphere and beyond. But power alone is not enough — you also need good stabilizing fins and thrust vectoring to keep your rocket steady as it flies. I felt like this part was lacking in the Go ecosystem of Datastar. By enforcing a common structure of types, methods and other conventions with tooling, Datapages provides not only the power but also the stability your rocket needs to stay in flight for long and consume as little brain fuel as possible.
Not only does Datapages allow you to start quickly with datapages init and jump straight into building your application, but it also continuously supports you keeping accidental complexity low by:
datapages gen to generate all boilerplate code consistently and guide you and your AI coding agents.datapages lint that can be used in CI/CD workflows for extensive static code analysis.datapages watch to give you an interactive hot-reload environment for a fast feedback loop with error reporting directly in the browser preview.Agentic coding is a big topic right now and likely here to stay. But LLMs tend to drift over time and introduce accidental complexity. So for AI to be used more effectively I wanted to provide the skills and instructions necessary for agents to know how to deal with this tech stack and call into Datapages CLI help them when they drift by providing them with useful feedback.
Datapages is a good fit if you:
See CONTRIBUTING.md for development setup and commands, and AGENTS.md for code style, testing conventions, commit message format and project structure.
Use the example/classifieds/ application as a real-world
test fixture when developing Datapages.
Go
92.6%
templ
3.7%
CSS
2.1%
A Datastar Go web frontend framework
90
stars
638
commits
Go
primary language
Sep 13, 2026
updated
[!WARNING] Alpha Software: Datapages is still in early development. APIs are subject to change and you may encounter bugs.
[!NOTE] v0.10 is coming with API improvements, stateful pages, service worker support, multi-app modules and more!
A Templ + Go + Datastar web framework for building dynamic, server-rendered web applications in pure Go.
Focus on your business logic, generate the boilerplate Datapages parses your app source package and generates all the wiring. Routing, sessions and authentication, SSE streams, CSRF protection, type-safe URL and action helpers, Prometheus metrics - so your application code stays clean and takes full advantage of Go's strong static typing and high performance.
No matter whether you're building real-time collaborative dynamic web app or simple HTMX-style websites - Datapages will serve you well.
counter — Real-time counter built twice in one module,
bare bones as app/simple and polished as app/fancy. Bare bones starting
point, and the example of a module that builds more than one application.todolist — Real-time collaborative todo list with per-tab
server-side state (Most Tao conform example).calculator — Hybrid calculator app that runs both as
a multi-client server and single-client Desktop app.classifieds —
Full-featured classifieds marketplace with sessions, auth, Prometheus metrics,
Grafana dashboards and load testing.tailwindcss —
Minimal static page demonstrating Tailwind CSS integration.webcomponents —
Landing page with vanilla and Lit-based Web Components
bundled via esbuild through a custom watcher.sqlitesessions —
Custom sessions.Manager implementation backed by SQLite
via sqinn-go (no cgo).go install github.com/romshark/datapages/cmd/datapages@latest
datapages init
| Command | Description |
|---|---|
datapages init | Initialize a new project with scaffolding and configuration. |
datapages gen | Parse the app model and generate the datapages package. |
datapages watch | Start the live-reloading development server. |
datapages lint | Validate the app model without generating code. |
datapages version | Print CLI version information. |
Nothing about the build is configured. Every setting is read from the code that already states it.
Static file serving is turned on by an embed.FS whose doc comment names the
URL path it is served at, the way a page names its route. The comment gives
the prefix, the //go:embed directive gives the directory:
// app/assets.go
// StaticFS is /static/
//go:embed static/*
var StaticFS embed.FS
The URL path in the comment must start and end with / and cannot be /.
The //go:embed directive must name exactly one directory inside the app
package.
The browsable argument of datapages.WithAssets lists a directory that has
no index.html. Pass browsable=false in production to avoid exposing every
embedded file.
The app package, the session data type, the metrics mode and the package to
generate into are the type arguments of the datapages.NewServer call.
s, err := datapages.NewServer[
app.App, // App
datapages.DisableSessions, // SessionData
datapages.DisablePrometheus, // Metrics
datapagesgen.Server, // S
](
a, broker, datapages.WithLogger(logger),
)
App names the app package. Metrics decides the Prometheus counters:
datapages.EnablePrometheus generates the code that counts and requires
WithPrometheus to serve it, datapages.DisablePrometheus generates no
counters, has no Prometheus imports and rejects that option. Use
datapages init --prometheus=false to scaffold a project whose entry point
names it.
S must name that app package's datapagesgen, which is where its code is
generated:
app/datapagesgen for ./app, app/frontend/datapagesgen for ./app/frontend.
One module may build any number of applications. Each app package gets its own model, its own generated package and its own entry point:
app/frontend/ cmd/frontend/
app/frontend/datapagesgen/
app/admindashboard/ cmd/admindashboard/
app/admindashboard/datapagesgen/
Events are the one thing the applications of a module share: two of them given
one broker publish into one namespace. No two of them may claim the same subject,
which datapages gen and datapages lint check over the whole module.
To let two applications receive each other's events, declare the event once in
a package both import and use that type in both, instead of declaring it twice.
datapages gen generates every one of them. datapages watch runs one, so a
module that builds more than one needs --app to say which:
datapages watch --app frontend
A module with no NewServer call yet is generated into app/datapagesgen
from ./app and gets a cmd/server/main.go written for it.
What is left is the tooling, which datapages.yaml or datapages.yml in the
module root carries. If both files exist, the CLI treats that as an error.
cmd: cmd/server
watch:
exclude:
- ".git/**" # git internals
- ".*" # hidden files/directories
- "*~" # editor backup files
These top-level keys are supported:
cmd: where datapages gen writes the first cmd/server/main.go,datapages watch builds while no NewServer call is written in a
main package yet. Default: cmd/server. Once such a call exists,
the command it is written in is the entry point and this key is unused,
which is why a module building several applications does not set it.
Must be a relative path inside the module:
an absolute path or a .. segment is rejected.watch: optional development server settings (app host, proxy timeout,
debounce, TLS, compiler flags, logging, custom watchers, etc.)See SPECIFICATION.md for the full source package specification, including handler signatures, parameters, return values, events, sessions, and modules.
See FAQ.md for frequently asked questions.
Datapages ships pluggable modules with swappable implementations:
Manager[Data]
Broker
TokenWriter, TokenValidator
Tokens - the built-in default: HKDF-SHA256 over the session token, BREACH-resistant masking, nothing to configureTokenGeneratorThe reason I built Datapages is that the combination of Datastar + Go + Templ is my preferred way of writing server-centric web applications. But in every project I used this tech stack for I kept repeating the same code patterns and solving the same problems over and over again. I realized many developers are repeating the same patterns too and struggle with the common pitfalls:
Your Datastar frontends are your rocket to extraterrestrial worlds of the internet. The further you want to go, the heavier a rocket you'll require. Hence, you need powerful boosters to get it off the ground and overcome Earth's gravity. Such boosters exist in the form of awesome templates like zangster300/northstar, which will quickly get your rocket to the stratosphere and beyond. But power alone is not enough — you also need good stabilizing fins and thrust vectoring to keep your rocket steady as it flies. I felt like this part was lacking in the Go ecosystem of Datastar. By enforcing a common structure of types, methods and other conventions with tooling, Datapages provides not only the power but also the stability your rocket needs to stay in flight for long and consume as little brain fuel as possible.
Not only does Datapages allow you to start quickly with datapages init and jump straight into building your application, but it also continuously supports you keeping accidental complexity low by:
datapages gen to generate all boilerplate code consistently and guide you and your AI coding agents.datapages lint that can be used in CI/CD workflows for extensive static code analysis.datapages watch to give you an interactive hot-reload environment for a fast feedback loop with error reporting directly in the browser preview.Agentic coding is a big topic right now and likely here to stay. But LLMs tend to drift over time and introduce accidental complexity. So for AI to be used more effectively I wanted to provide the skills and instructions necessary for agents to know how to deal with this tech stack and call into Datapages CLI help them when they drift by providing them with useful feedback.
Datapages is a good fit if you:
See CONTRIBUTING.md for development setup and commands, and AGENTS.md for code style, testing conventions, commit message format and project structure.
Use the example/classifieds/ application as a real-world
test fixture when developing Datapages.
Go
92.6%
templ
3.7%
CSS
2.1%