{"id":34148567,"url":"https://github.com/julvo/tinystatic","last_synced_at":"2026-03-12T03:32:13.152Z","repository":{"id":44701770,"uuid":"248330377","full_name":"julvo/tinystatic","owner":"julvo","description":"A tiny static website generator which is flexible and easy to use","archived":false,"fork":false,"pushed_at":"2022-09-15T10:21:44.000Z","size":65,"stargazers_count":36,"open_issues_count":0,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-12-17T19:45:11.566Z","etag":null,"topics":["html","static-site","static-site-generator","static-website","template"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/julvo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-18T20:00:27.000Z","updated_at":"2025-04-19T19:57:57.000Z","dependencies_parsed_at":"2022-09-05T11:30:17.792Z","dependency_job_id":null,"html_url":"https://github.com/julvo/tinystatic","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/julvo/tinystatic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julvo%2Ftinystatic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julvo%2Ftinystatic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julvo%2Ftinystatic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julvo%2Ftinystatic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/julvo","download_url":"https://codeload.github.com/julvo/tinystatic/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julvo%2Ftinystatic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30414301,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-12T00:40:14.898Z","status":"online","status_checked_at":"2026-03-12T02:00:07.260Z","response_time":114,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["html","static-site","static-site-generator","static-website","template"],"created_at":"2025-12-15T04:48:17.176Z","updated_at":"2026-03-12T03:32:13.146Z","avatar_url":"https://github.com/julvo.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tinystatic \n\n![logo.png](https://github.com/julvo/tinystatic/blob/master/logo.png \"tinystatic logo\")\n\nA tiny static website generator that is flexible and easy to use. It's flexible, as there is no required website structure nor any blog-specific concepts. It's easy to use, as we can start with a standard HTML site and introduce tinystatic gradually.\n\nThe concept of tinystatic is simple: From every file in an input directory, create a file in an output directory which we can then use as the public directory of our webserver. How tinystatic generates an output file depends on the input file extension: Markdown is converted to HTML, while CSS, JS and images are simply copied. For markdown and HTML files, you can specify meta data at the top of a file. By specifying a template in this file meta data, and providing templates in separate directories, you can make use of Go's HTML templating engine. [Here](https://github.com/julvo/tinystatic/tree/master/examples/blog) an example of a typical blog website and for a quick start guide, see below.\n\n## Install\n\n### Pre-built binaries\nDownload the tinystatic binary for your operating system:\n- [Linux](https://github.com/julvo/tinystatic/releases/download/v0.1.0/tinystatic_linux_amd64) \n- [macOS](https://github.com/julvo/tinystatic/releases/download/v0.1.0/tinystatic_macos_darwin_amd64) \n\nOptionally, add the binary to your shell path, by either placing the binary into an existing directory like `/usr/bin` or by adding the parent directory of the binary to your path variable.\n\nIf you added tinystatic to your path, you should be able to call\n```shell\ntinystatic -help\n```\nOtherwise, you will need to specify the path to the tinystatic binary when calling it\n```shell\n/path/to/tinystatic -help\n```\n\n### Compiling from source\nIf you don't want to use the pre-built binaries, you will need to install the Golang compiler to compile tinystatic. Then, you can install tinystatic by running\n```shell\ngo install -u github.com/julvo/tinystatic\n```\nor by cloning the repository and running `go install` or `go build` in the root directory of this repository.\n\n## Quick start\nThis is a 10-minute tutorial in which we build a small blog, starting with a single HTML page and introducing the features of tinystatic one-by-one.\n\nFirst, we create a folder called `routes`. Inside this folder, we create a single HTML file `index.html` with the following contents:\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eOur first tinystatic website\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n      \u003ch1\u003eWelcome to our blog\u003c/h1\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nNow, we can run `tinystatic` for the first time. By default, tinystatic expects to be called in the directory containing the `routes` directory, but you can change that by using the `-routes` parameter. After running the command, you should see a folder `output` appearing next to the `routes` folder. Our file structure now looks like this:\n```\nmy-blog/\n    routes/\n        index.html\n    output/\n        index.html\n```\nWe can now run a webserver in the output directory, e.g. using Python's built-in server to open our website on `http://localhost:8000`:\n```\ncd output\npython3 -m http.server\n```\n\nSo far, all tinystatic did was copying the `index.html` from `routes` to `output` - not all that useful, but hang in...\n\nLet's add a second HTML file to `routes`, e.g. `about.html`:\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eOur first tinystatic website\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n      \u003ch1\u003eAbout us\u003c/h1\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nAfter we run `tinystatic` again, and with our webserver still running, we can now navigate to `http://localhost:8000/about`. Note how there is no `.html` in this route anymore, as tinystatic created a folder `about` with a single `index.html` in it, like so:\n```\noutput/\n    index.html\n    about/\n        index.html\n```\n\nWhat we don't like about our current pages is the duplication of all the basic HTML structure. Wouldn't it be better to use a shared template for `index.html` and `about.html`?. To do this, we create a folder called `templates` next to our `routes` folder and place an HTML file `default.html` inside it: \n\n```\nmy-blog/\n    routes/\n        index.html\n        about.html\n    templates/\n        default.html\n```\nThe content of `default.html` should be:\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eOur first tinystatic website\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n      {{template \"body\" .}}\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nAlso, we change the content of `routes/index.html` to\n```html\n---\ntemplate: default.html\n---\n{{define \"body\"}}\n\u003ch1\u003eWelcome to our blog\u003c/h1\u003e\n{{end}}\n```\n\nand the content of `routes/about.html` to \n```html\n---\ntemplate: default.html\n---\n{{define \"body\"}}\n\u003ch1\u003eAbout us\u003c/h1\u003e\n{{end}}\n```\n\nWhen running `tinystatic` again, the output is identical to the previous output, but we consolidated the HTML skeleton into a single place.\n\nAs seen just now, we can specify a template to render our content into by providing a template name in the meta data at the top of a file. We can also include other templates (see below) and use Go's template pipelines. While rendering, we have access to the meta data defined at the top of the file, a struct `Route` with fields `Route.Href`, `Route.FilePath` and `Route.Meta` which is again a map of meta data defined at the top of the file. Moreover, we can access `Routes`, which is a slice (think: array for people new to Go) of all routes, which we will learn more about further down.  \n\nLet's use this meta data together with Go's templating primitives to change the page title depending on the current page. For this, we change the meta data in `routes/about.html` to\n```\n---\ntemplate: default.html\ntitle: About\n---\n```\n\nand finally change `templates/default.html` to\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003e{{if .title}} {{.title}} | {{end}}Our first tinystatic website\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n      {{template \"body\" .}}\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nAfter regenerating the website, the browser should now display different page titles for our index and our about page.\n\nNow, let's create a few blog posts in our routes folder, e.g.\n```\nroutes/\n    index.html\n    about.html\n    posts/\n        first_post.md\n        second_post.md\n```\n\nPlace some markdown inside these `.md` files with a meta data section at the top specifying the template as `default.html`, similar to how we specified the meta data in `routes/index.html` and `routes/about.html`. For `first_post.md`, this could look like this:\n```markdown\n---\ntemplate: default.html\ntitle: First Post\n---\n\n# Here could be some fine content\n\n```\n\n\nRunning `tinystatic` again to regenerate the output, we can now visit `http://localhost:8000/posts/first_post` and `http://localhost:8000/posts/second_post`. The markdown has been converted HTML and placed inside a template called `body` for us, so that it renders into the `{{template \"body\" .}}` placeholder in `templates/default.html`. Note how this is different to `.html` files, where we need to call `{{define \"body\"}} ... {{end}}` manually.\n\nNext, let's create a listing of our posts by using the aforementioned `Routes` slice. We change the content of `routes/index.html` to:\n```html\n---\ntemplate: default.html\n---\n{{define \"body\"}}\n\u003ch1\u003eWelcome to our blog\u003c/h1\u003e\n\n\u003cul\u003e\n{{range .Routes | filterFilePath \"**/posts/*.md\"}}\n\u003cli\u003e\n    \u003ca href={{.Href}}\u003e{{.title}}\u003c/a\u003e\n\u003c/li\u003e\n{{end}}\n\u003c/ul\u003e\n```\n\nAfter regenerating, we should see a list of our posts on the index page. The `Routes` slice provides a list of all routes which we can filter using pre-defined helper functions, e.g. \n- `.Routes | filterFilePath \"**/posts/*.md\"` to display all files ending on `.md` in any folder called posts\n- `.Routes | sortAsc \"title\"` to sort routes based on the meta data field `title`\n- `.Routes | limit 10` to get only the first 10 routes\n- `.Routes | offset 3` to skip the first three routes\n- `.Routes | filter \"title\" \"*Post\"` to filter based on the meta data field `title` matching the pattern `*Post`\n- `.Routes | filterFileName \"*.md\"` to get all files ending on `*.md`\n- `.Routes | filterHref \"/*\"` to get all top-level routes\n- `.Routes | filterFilePath \"**/posts/*.md\" | sortDesc \"title\" | limit 10` to combine some of the above\n\nNext, we would like to use a different layout for posts than for the other pages. The posts should have an image before the text, whereby we want to define the image URL in the post meta data. Therefore, we add a second template called `templates/post.html` with the following content:\n\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003e{{if .title}} {{.title}} | {{end}}Our first tinystatic website\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n      \u003cimg src={{.image}} /\u003e\n      {{template \"body\" .}}\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nWe change the post meta data to\n```\n---\ntemplate: post.html\ntitle: First Post\nimage: https://some-image.url\n---\n```\nRegenerating the output should give us a beautiful image above our post. However, we also ended up with duplicated HTML code in our templates again. To improve that, we create another folder next to `routes` and `templates` called `partials`. Inside partials, we create a file called `head.html` with\n```html\n{{define \"head\"}}\n\u003chead\u003e\n  \u003ctitle\u003e{{if .title}} {{.title}} | {{end}}Our first tinystatic website\u003c/title\u003e\n\u003c/head\u003e\n{{end}}\n```\nand we replace `\u003chead\u003e...\u003c/head\u003e` in our templates with `{{template \"head\" .}}`, like so\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n  {{template \"head\" .}}\n  \u003cbody\u003e\n      {{template \"body\" .}}\n  \u003c/body\u003e\n\u003c/html\u003e\n```\nNow we reduced the code replication between different templates to a minimum. We can use this `partials` directory to store all kinds of reoccuring components, e.g. navigation bars or footers.\n\nNote that we don't actually need to structure the project using the folder names that we used in this tutorial. These folders names are merely the defaults, but can be changed using the respective command line arguments (see `tinystatic -help` for more).\n\nThere is a full example of a blog [here](https://github.com/julvo/tinystatic/tree/master/examples/blog).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjulvo%2Ftinystatic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjulvo%2Ftinystatic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjulvo%2Ftinystatic/lists"}