Skip to content
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
156 lines (96 sloc) 8.04 KB

Hugo + NetlifyCMS = HugolifyCMS

This tutorial demonstrates how to integrate Hugo generated site and Netlify CMS, with N levels (nested sections/folders). It is easily exportable to other SSG



Live demo


  • Hugo with nested folders integrated with NetlifyCMS
  • Multilanguage (Netlifycms and Hugo support for multilanguage are incompatibles by now)
  • CMS accessible from live site
  • It works with Netlify Identity and Github Auth: main problem here was creating new sections paths in content folder.


  • Hugo is great to manage static sites
  • Netlify CMS is an amazing and easy to use CMS in front of static site generators (and awesome if you deploy your web to Netlify)
  • If your Hugo site has a structure based on nested folders, is OK from Hugo side but difficult from Netlify CMS.
  • This strategy will help you to manage both, and from your live site, access to NetlifyCMS administration only for the current section you are visiting (content folder from Hugo). This simplifies the lookup for content, because you access it from your live site and then you edit it.


Fork the project from github interface


	$ git clone

(OPTIONAL) if you want to build the repo locally, you need to execute from your repo root

	$ node tasks/rename-languages.js 
	$ hugo

When you publish to your repo, rename content files to {{filename}}-{{language}}.md

	$ node ./tasks/rename-languages.js -


	$ git add -A
	$ git commit -m "new version"		
	$ git push

Netlify setup

Deploy to Netlify

(change the url with your own repo)

  1. Build command:

     $ node ./tasks/rename-languages.js && node ./tasks/create-relative-cms.js && hugo

    deploy settings

  2. Setup Netlify Identity

  3. Setup Netlify Git Gateway

Azure setup

Deploy to Azure

  1. Setup your application in a free tier
  2. Setup an environment variable for NodeJS version 8.5.0 (minimum version, to use nodejs to rename languages and relative cms)

Azure Setup


Key files to setup this strategy

1) Nodejs files to help the build process

  • Rename languages: rename-languages.js

    • it changes between Hugo and Netlify language management (in fact, Netlify doesn't manage languages in filenames)
    • when you build to store in git, you need to set filenames to {{filename}}-{{language}}.md
    • when you build to generate HTML, you need to set filenames to {{filename}}.{{language}}.md
  • Create relative CMS to content/section: create-relative-cms.js

2) CMS in the footer of the live site

  • Hugo partial template for CMS

    • cms.html

    • it adds links to login (netlify identity), create new sections, new pages, edit pages, ...

    • this template is only visible if param cms=true is attached to the url.

      Footer CMS

  • Static file cms.js to manage visibility and "create section" directly to git

    • It push a version of static/admin/ to git for every of your configured languages. You can setup your frontmatter accordingly to your content type in config.yml
  • There are two "instances" of Netlify CMS:

3) Files to import into your project

  • You can copy directories static, layouts and tasks into your Hugo site, and include in your footer.html an include to the cms partial template.

Sections explained

It's not possible (April 2018) to create a new path in github from Netlify CMS. It's not possible setup config.yml "folder" with a dynamic value from files, or in case you put a variable in the slug (e.g slug: /{{folder}}/ it gets sanitized and folder isn't created.

Then, the best way now is to access directly to github. This is done through Netlify Git Gateway (easy way) or through Git Auth Workflow. All the staff is in cms.js and it can be improved :)

Github Auth is the easiest way to deploy sites outside netlify, you only need a custom auth app like these:

Hard way is with Netlify Git Gateway and Gotrue, but is better because users can access to limited resources and they don't need a Github account

You can’t perform that action at this time.