{"id":13718669,"url":"https://github.com/spech66/hugo-best-practices","last_synced_at":"2025-04-07T14:12:56.715Z","repository":{"id":44646636,"uuid":"154175666","full_name":"spech66/hugo-best-practices","owner":"spech66","description":"Best practices and ideas for Hugo the open-source static site generator.","archived":false,"fork":false,"pushed_at":"2024-03-23T10:50:33.000Z","size":42,"stargazers_count":284,"open_issues_count":0,"forks_count":15,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-03-31T12:05:45.056Z","etag":null,"topics":["best-practices","checklist","hugo","hugo-documentation","hugo-site","hugo-theme"],"latest_commit_sha":null,"homepage":"https://www.spech.de","language":"Shell","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/spech66.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":"https://www.paypal.me/SPech/5"}},"created_at":"2018-10-22T16:17:10.000Z","updated_at":"2025-03-13T11:45:58.000Z","dependencies_parsed_at":"2024-03-23T12:21:08.921Z","dependency_job_id":"6cddd83d-4ff5-4842-a934-94d2b2904d99","html_url":"https://github.com/spech66/hugo-best-practices","commit_stats":{"total_commits":39,"total_committers":4,"mean_commits":9.75,"dds":0.3076923076923077,"last_synced_commit":"3ba08bef9eb29684db01da833c5d149caaf182b6"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spech66%2Fhugo-best-practices","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spech66%2Fhugo-best-practices/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spech66%2Fhugo-best-practices/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spech66%2Fhugo-best-practices/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spech66","download_url":"https://codeload.github.com/spech66/hugo-best-practices/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247666014,"owners_count":20975788,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["best-practices","checklist","hugo","hugo-documentation","hugo-site","hugo-theme"],"created_at":"2024-08-03T01:00:35.586Z","updated_at":"2025-04-07T14:12:56.689Z","avatar_url":"https://github.com/spech66.png","language":"Shell","funding_links":["https://www.paypal.me/SPech/5"],"categories":["Shell","Resources"],"sub_categories":["Non-Official"],"readme":"# Hugo - Best practices\n\nBest practices and ideas for [Hugo](https://gohugo.io/) the open-source static site generator.\n\nThemes based on this best practices: [Bootstrap-BP](https://github.com/spech66/bootstrap-bp-hugo-theme), [Materialize-BP](https://github.com/spech66/materialize-bp-hugo-theme),\n[Bootstrap-BP hugo startpage](https://github.com/spech66/bootstrap-bp-hugo-startpage).\n\n## Table of contents\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [Hugo - Best practices](#hugo---best-practices)\n  - [Table of contents](#table-of-contents)\n  - [Content organization](#content-organization)\n  - [Git repository and CI Tools](#git-repository-and-ci-tools)\n  - [Content types and archetypes](#content-types-and-archetypes)\n  - [Configure the site](#configure-the-site)\n  - [CSS and JavaScript](#css-and-javascript)\n    - [CSS](#css)\n    - [Javascript](#javascript)\n    - [Conditionals](#conditionals)\n  - [Images](#images)\n  - [Caching and .htaccess](#caching-and-htaccess)\n  - [Add a Schema.org partial](#add-a-schemaorg-partial)\n  - [External links in new window](#external-links-in-new-window)\n  - [Front-End Checklist](#front-end-checklist)\n  - [Tools](#tools)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Content organization\n\nKeep all images next to the index Markdown file. This allows to keep the images in the highest possible resolution and let hugo resize them to the perfect size for the current theme (see [Images](#images) below).\n\n```sh\n├── mysite/\n    ├── content/\n    │   └── posts/\n    │       ├── 0001-firstpost/\n    │       │   ├── index.md\n    │       │   └── me.jpg\n    │       ├── 0002-secondpost/\n    │       │   ├── index.md\n    │           └── fun.jpg\n    ├── about/\n    │   └── index.md\n```\n\nThere is a Discussion on this in the [Forum](https://discourse.gohugo.io/t/discussion-content-organization-best-practice/6360/2).\n\n## Git repository and CI Tools\n\nKeep your site in a version control system like Git. This provides backup, history and multi user editing out of the box.\n\nUse Continuous Integration/Deployment to publish your website after git push. Simple solutions like [webhook](https://github.com/adnanh/webhook/) might do the job. For complex scenarios you might want to use something like [Jenkins](https://jenkins.io/). For most cases Jenkins will be overkill.\n\nYou can sync files using `rsync` after a successful build. Have a look at the provided `deployment` scripts in this repository.\n\n## Content types and archetypes\n\nDefine your required types. A blog usually goes with pages and posts. Pages won't have fields like the author or creation dates displayed.\nPages are usually reached under their name directly. Posts will be posted several times a month and might have a structure like `/year/month/name`.\nThe archetypes should reflect the data that is needed for the content. Posts should have tags and categories applied.\n\n```yaml\n[permalinks]\n    posts = \"/:year/:month/:slug/\"\n    page = \"/:slug/\"\n```\n\nThis might be the archetype for posts. I prefect to collect all categories and tags in the archetype so I can remove all unused ones for the new blog post.\n\n```yaml\n---\ntitle: \"{{ replace .Name \"-\" \" \" | title }}\"\nauthor: Sebastian\ntype: post\ndate:  {{ now.Format \"2006-01-02\" }}\nfeatured_image: myimage.jpg\ndraft: true\ncategories:\n  - A\n  - B\n  - C\ntags:\n  - Hugo\n  - Game Development\n  - Internet of Things (IoT)\n  - Linux\n  - ...\ndescription: xxx\n---\n\nCONTENT\n\n\u0026nbsp;\n\nSource: xyz\n```\n\n## Configure the site\n\nConfigure your new site with all relevant [options](https://gohugo.io/getting-started/configuration/). These are helpful values to start with.\n\n```yaml\n# Settings\nbaseURL = \"https://www.spech.de/\"\nlanguageCode = \"de-DE\" # or en-US\ntitle = \"My hugo page\"\ndescription = \"Nice page\"\n# theme = \"hugo-future-imperfect\" # \u003c- you won't need this as we copy the theme data!\ncanonifyURLs = true\ncopyright = \"Sebastian Pech\"\nenableRobotsTXT = true\n\n[sitemap]\n    changefreq = \"weekly\"\n    priority = 0.5\n\n[permalinks]\n    posts = \"/:year/:month/:slug/\"\n    page = \"/:slug/\"\n```\n\nMake sure to send your `sitemap.xml` file to [Google Search Console](https://www.google.com/webmasters/tools/home), [Bing Webmaster Tools](https://www.bing.com/toolbox/webmaster), ...\n\n## CSS and JavaScript\n\nOld themes kept the css and js files in the static folder. Sometimes tools like Gulp, Grunt and Webpack were used for pre-processing.\nThe latest version of Hugo will do all the stuff like bundling and minifying for you. For this to work the files have to be put in the `assets` folder.\n\nThere are three critical methods to use as the bare minimum `minify`, `fingerprint` and `slice`. SCSS might make use of `toCSS` and `postCSS`.\n\nWith `minify` you will get a minified version of your files. ([Hugo Documentation](https://gohugo.io/hugo-pipes/minification/))\n\nThe `fingerprint` adds a unique string to the name so that the browser won't cache your files on modification. ([Hugo Documentation](https://gohugo.io/hugo-pipes/fingerprint/))\n\nFinally `slice` allows you to concat multiple files to a new one. This works best with `minify`. ([Hugo Documentation](https://gohugo.io/hugo-pipes/bundling/))\n\n### CSS\n\nPutting the above methods in place the minified `main.css` will be created as described below. Keep in mind that the files has to be in the `assets` folder.\n\n```html\n{{ $stylemain := resources.Get \"css/main.css\" | minify | fingerprint \"sha512\" }}\n\u003clink rel=\"stylesheet\" href=\"{{ $stylemain.RelPermalink }}\" integrity=\"{{ $stylemain.Data.Integrity }}\"\u003e\n```\n\nFor processing SCSS Hugo provides two functions. ([Hugo Documentation](https://gohugo.io/hugo-pipes/postcss/))\n\n```html\n{{ $stylemain := resources.Get \"scss/main.scss\" | toCSS | postCSS (dict \"use\" \"autoprefixer\") | minify | fingerprint \"sha512\" }}\n\u003clink rel=\"stylesheet\" href=\"{{ $stylemain.RelPermalink }}\" integrity=\"{{ $stylemain.Data.Integrity }}\"\u003e\n```\n\nCombining all css files to one minified file allows fewer HTTP requests. This is done using `slice`.\n\n```html\n{{ $cssbootstrap := resources.Get \"/css/bootstrap.css\" }}\n{{ $cssmain := resources.Get \"/css/main.css\" }}\n{{ $csscustom := resources.Get \"/css/custom.css\" }}\n{{ $allcss := slice $cssbootstrap $cssmain $csscustom | resources.Concat \"/css/vendor.css\" | minify | fingerprint \"sha512\" }}\n\u003clink rel=\"stylesheet\" href=\"{{ $allcss.RelPermalink }}\" integrity=\"{{ $allcss.Data.Integrity }}\"\u003e\n```\n\n### Javascript\n\nUsually a theme will contain multiple JS files which might require a specific order. This is where `slice` comes into handy.\n\n```html\n{{ $jquery := resources.Get \"/js/jquery-v6.6.6/jquery.min.js\" }}\n{{ $bootstrap := resources.Get \"/js/bootstrap-v4.6.0/bootstrap.min.js\" }}\n{{ $main := resources.Get \"/js/main.js\" }}\n\n{{ $fullscript := slice $jquery $bootstrap $main | resources.Concat \"/js/vendor.js\" | minify | fingerprint \"sha512\" }}\n\u003cscript src=\"{{ $fullscript.RelPermalink }}\" integrity=\"{{ $fullscript.Data.Integrity }}\"\u003e\u003c/script\u003e\n```\n\n### Conditionals\n\nAll scripts and styles that are needed only on specific pages should be wrapped in conditionals.\n\n```html\n{{ if .Params.customPageColor }}\n    \u003cstyle\u003e\n        body { background-color: red; }\n    \u003c/style\u003e\n{{ end }}\n```\n\n```html\n{{ if .Params.contactScript }}\n    \u003cscript src=\"/js/my-contact-script.js\"\u003e\u003c/script\u003e\n{{ end }}\n```\n\n## Images\n\nImage files should never be larger than necessary.\n\nHugo allows you to create resources from `.Params` information ([Hugo Documentation](https://gohugo.io/hugo-pipes/resource-from-string/)).\nThe resources can be processed with the image processing functions from Hugo afterwards ([Hugo Documentation](https://gohugo.io/content-management/image-processing/)).\nThis allows you to keep the original images next to the Markdown files (as mentioned before) and let Hugo generate thumbnails and smaller versions.\n\n```html\nfeatured_image: my-blog-header-1.jpg\n```\n\nThis example resizes the image mentioned in the `featured_image` parameter of the blog page to a version with 800 pixel width.\n\n```html\n{{ if .Params.featured_image }}\n    {{ $siteurl := (.RelPermalink) }}\n    {{ $sitetitle := (.Title) }}\n    {{ with .Resources.GetMatch (.Params.featured_image) }}\n        {{ $thumb := .Resize \"800x\" }}\n        \u003cimg src=\"{{ $thumb.Permalink }}\" alt=\"{{ $sitetitle }}\"\u003e\n    {{ end }}\n{{ end }}\n```\n\n## Caching and .htaccess\n\nSee the example `.htaccess` in the `static` folder. It covers the following points.\n\n- Redirects for old content\n- Compression\n- Caching\n- SSL\n- HSTS and Content Security Policies\n- Errror documents\n- Wordpress migration rules\n\nMake sure you understand every rule before applying it! The Content-Security-Policy might break your page if you rely on external sources.\n\n## Add a Schema.org partial\n\n**UPDATE:** Even better use Hugo [internal templates](https://gohugo.io/templates/internal/) for this.\n\n**UPDATE (Hugo \u003e= 0.60.0):** According to the patch notes Hugo processes the images in a new order. `The image logic in the 3 SEO internal templates twitter_cards.html, opengraph.html, and schema.html is consolidated: images page param first, then bundled image matching *feature*, *cover* or *thumbnail*, then finally images site param.`\n\nAdd a Schema.org partial according to [](https://keithpblog.org/post/hugo-website-seo/).\n\n```html\n# layouts/partials/header.html\n...\n{{ partial \"seo_schema\" . }}\n\u003ctitle\u003e\n...\n```\n\n```js\n// layouts/partials/seo_schema.html\n\u003cscript type=\"application/ld+json\"\u003e\n{\n    \"@context\" : \"http://schema.org\",\n    \"@type\" : \"BlogPosting\",\n    \"mainEntityOfPage\": {\n         \"@type\": \"WebPage\",\n         \"@id\": \"{{ .Site.BaseURL }}\"\n    },\n    \"articleSection\" : \"{{ .Section }}\",\n    \"name\" : \"{{ .Title }}\",\n    \"headline\" : \"{{ .Title }}\",\n    // \"description\" : \"{{ if .Description }}{{ .Description }}{{ else }}{{if .IsPage}}{{ .Summary }}{{ end }}{{ end }}\",\n    \"description\" : \"{{ with .Description }}{{ . }}{{ else }}{{ .Site.Params.description }}{{ end }}\"\n    \"inLanguage\" : \"{{ .Lang }}\",\n    \"author\" : \"{{ range .Site.Author }}{{ . }}{{ end }}\",\n    \"creator\" : \"{{ range .Site.Author }}{{ . }}{{ end }}\",\n    \"publisher\": \"{{ range .Site.Author }}{{ . }}{{ end }}\",\n    \"accountablePerson\" : \"{{ range .Site.Author }}{{ . }}{{ end }}\",\n    \"copyrightHolder\" : \"{{ range .Site.Author }}{{ . }}{{ end }}\",\n    \"copyrightYear\" : \"{{ .Date.Format \"2006\" }}\",\n    \"datePublished\": \"{{ .Date | safeHTML }}\",\n    \"dateModified\" : \"{{ .Date | safeHTML }}\",\n    \"url\" : \"{{ .Permalink }}\",\n    \"wordCount\" : \"{{ .WordCount }}\",\n    \"keywords\" : [ {{ if isset .Params \"tags\" }}{{ range .Params.tags }}\"{{ . }}\",{{ end }}{{ end }}\"Blog\" ]\n}\n\u003c/script\u003e\n```\n\nI modified the example with `{{ .Date | safeHTML }}` otherwise Hugo replaces the + for positive timezones (like GTM, MEZ, ...) with a HTML escaped sequence which makes the javascript illegal for HTML check tools.\n\nSetting .Site.Author is a bit tricky. Use this snippet.\n\n```toml\n[Author]  \n  name = \"Sebastian Pech\"\n```\n\n## External links in new window\n\nStarting with Hugo 0.60 and the *Goldmark* parser external **links** won't open in a **new window**. The `hrefTargetBlank` from *Blackfriday* is not supported in *Goldmark*.\nIn the [hugo-shortcodes](https://github.com/spech66/hugo-shortcodes) collection the `render-link.html` shortcode will fix the problem. Put the file in `\\layouts\\_default\\_markup` and alls urls starting with http(s) will get the `target=\"_blank\" rel=\"noopener noreferrer\"` properties.\n\n## Front-End Checklist\n\nWalk trough every point in the [Front-End Checklist](https://github.com/thedaviddias/Front-End-Checklist) and the [Front-End Performance Checklist](https://github.com/thedaviddias/Front-End-Performance-Checklist).\n\n## Awesome Hugo list\n\nAdditional links and resources can be found at [Awesome Hugo](https://github.com/theNewDynamic/awesome-hugo). *A curated list of awesome things related to Hugo.*\n\n## Tools\n\nThere are some tools and websites that can validate your page and check the speed.\n\n- [webhint](https://webhint.io/scanner/) _is a linting tool that will help you with your site's accessibility, speed, security and more, by checking your code for best practices and common errors._\n- [Varvy SEO tool](https://varvy.com/) _See how well a page follows the Google guidelines._\n- [Google Structured Data Testing Tool](https://search.google.com/structured-data/testing-tool) Helps validating the structured data on the website.\n- [Google PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/) checks performance, loading times and image sizes.\n- [Google Lighthouse](https://developers.google.com/web/tools/lighthouse/) performs audits on website performance, best practices, accessibility and SEO.\n- [SSL Server Test](https://www.ssllabs.com/ssltest/index.html) is a _free online service performing a deep analysis of the configuration of any SSL web server on the public Internet._\n- [Mozilla SSL Configuration Generator](https://ssl-config.mozilla.org/) _An easy-to-use secure configuration generator for web, database, and mail software._\n- [SEORCH](https://seorch.de/) German SEO testing tool.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspech66%2Fhugo-best-practices","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspech66%2Fhugo-best-practices","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspech66%2Fhugo-best-practices/lists"}