2025-08-14
Making webapps using Golang Tailwind Templ Htmx Sqlc
Code here: https://github.com/domi-ninja/gotths-example
GoTTHS - Golang Tailwind Templ Htmx Sqlc
The whole fun of doing full-stack go is cooking your own stack. There are some like it, but this one is mine.
Inspired by
Reasoning for technolgies used
- Tailwind: I am fine with using plain CSS with variables, but prefer tailwind. As a bonus, this allows me to use things like https://daisyui.com/htmx-component-library/. It also makes it so that ai-generated styles are less likely to break existing styles in other places (not local to the component).
- Templ: Inspired by pocketbase, I have tried using a thin wrapper around
html/template
for server side rendering. It worked fine, but similar to tailwind, I have concluded that it is worth using. In this case, the slight annoyances are worth it to recieve some compile-time type safety for the templates, and for being able to use the database models generated by sqlc directly in my templates - HTMX is one of the many fun ways to make the server side rendered pages come to life. I am very familiar with it, but there is many other mini-frameworks that would do the same jobs just as well
- SQLC: SQLC is used for generating models and functions for interacting with a relational DB. It occupies a sweet spot between an ORM and having to write your own DB interfaces with a bunch of copy-pasting, and I feel very good about using this.
Files
$ tree -L 2
.
├── app.go entry point and routing
├── app.toml config file for our app
├── cmd
│ └── server
├── data.db sqlite3 db file for development
├── frontend
│ ├── assets frontend blobs
│ ├── components templ reused page components
│ ├── layouts templ layout components
│ ├── tailwind.config-v3.js configure tailwind here
│ ├── tailwind-input-v3.css change styles here
│ └── views templ actual views / partial views
├── go.mod
├── goose.sh bash wrapper for goose command
├── go.sum
├── handle_index.go handler for /
├── handle_post_postid_DELETE.go handler for delete existing post: DELETE to /post/{postId}
├── handle_posts_POST.go handler for creating new post: POST to /posts
├── handle_posts_postid_GET.go handler for rendering post: GET to /post/{postId}
├── handle_reload_WS.go websocket demo and `/reload` dev utility
├── handler_utils.go http handler utils for less code
├── internal
│ └── db_generated db binding code generated by sqlc
├── Makefile interact with this project using make
├── README.md
├── sql
│ ├── migrations numbered goose migrations
│ └── query named sqlc queries
├── sqlc.yaml
└── webhelp some minimal framework stuff that might be reused
├── config.go config parser
├── env_dev.go prod vs dev compile time differences example
├── env_prod.go ^
├── logger.go logger middleware that helps find where in the code things happen
├── render.go wrapping templ rendering in case we need that
├── utils.go
└── webhelp.go
Dev features
- All changes result in a recompile via
air
, which then triggers an homemade websocket-based page refresher in the browser (reload.js
) - Makefile
PRs welcome
This is a very small example, not a fully featured template. I have not researched if a good one exists.
This may never change since golang is very well suited to handknitted software like this. Still, one never knows
Missing features that would be cool to have
- [ ] Auth via a provider
- [ ] Auth, handrolled, but convering all the weird edge cases
- [ ] File upload using a configured S3 service
- [ ] A nice way to do form validation
- [ ] Common frontend components, e.g. Date and Calendar, using something like daisyui perhaps?
- [ ] Some sort of deployment story in addition to “golang can compile everything into a blob, figure it out yourself”