Creating Pages from Data Programmatically for Hugo

UPDATED: APR 27, 2023 | PUBLISHED: APR 13, 2022 | 3.29k words, 16 minute read — GUIDES

So you’re using the Hugo static site generator and interested in auto-generating pages from data, similar to Gatsby’s programmatic generation or Middleman’s Dynamic Pages ? As of late 2021, Hugo does not have built-in support, and since the topic has been in discussion since at least 2013 , don’t hold your breath. Luckily, there’s options available to accomplish the same task, from premade tools to writing your own simple scripts.

How it Works 🔗︎

While Hugo itself may not have support for creating pages from a data source, as long as you generate files in locations it expects, you end up with the same outcome. The following approaches all follow the process of taking input data (often in JSON or YAML), generating Markdown files based off it, and placing them into the content/ folder. Though it’s the most common case, it’s not only for Markdown, the same process could be used for HTML template files, or any other file Hugo recognizes.

Programmatically creating pages 🔗︎

Github: Hugo-Data-to-Pages 🔗︎

A Node.js project which handles the content generation process, all you need to do is install it’s dependencies and you’re ready to go. I would have used this option if I had found it before I created my custom script.

Dedicated CMS + Build Plugin 🔗︎

For easier content management than a JSON file, explore the many CMS’s available in the wild. Check if they have the capability to connect with your website hosting provider’s build process, then it can generate pages from your data each time it builds the site. One combination with an extensive tutorial is Hugo + Sanity.io + Netlify .

Custom Script 🔗︎

If you want direct control of exactly what’s happening with your files, you can write your own custom script in whatever language you choose. I personally chose to use a Python script + a YAML data file for my first version, but unfortunately pyyaml isn’t in the standard library. If you don’t want to bother with managing Python dependencies (I’m in that same boat), there is an improved script below that uses only JSON for the configuration files.

Whether the config is handled through YAML, JSON, or whatever flavor of the month, I use a simple Makefile to handle the process: generating new pages, cleaning out existing content, and putting the fresh set in.

bsuuhehp--pciurudyplgvgarrtdoeotmmh::eo/s-np-ei/agrdpctgcveaooeeagno_rsetlg-:_esem-gn.niDetp/nny*i-ifbdye/laco/oc*natlehnots/ti:d1e3a1/3

Using YAML (1 Python Dependency) 🔗︎

For the script using YAML, an abridged version of tools.py looks like:

iGIddddltd{{"#imEDeeeeaiafi"fpNEffffyttrd"ToEAoleoeOrR_myffyrcwpg#ffpue:naDr_mtAFamoeaerireroat:t.OenaTIilrtmtetingorg:'_g:tairILn_cluahneene"{meumneOE(ckieh_rtftrntkf_'{iatdre(,N)o,fl_fneo.(ae_,rciidt(on_)_=:nvsdi_pwftrmvooddet'_yDtkealyier"eaanneeaermpaI"eipfp:pteadni[_ttittaa.raoa=mRdnn=rorrame(t*ietn_e'[g}wrg=lat=irii(=lape]demn'e_ee=tynnny._a(etriatttc_"a=m'tiptespppcttaolptcfahdti(oic_"/li(drrxararr((mpoahoi_e=et=t'nno_pif_dfeiycfitieffleag,nnpaeldttnmadece"an:eenhna""_nde'tiaf".rfeaeetagetoa[tcppr_ttt[[f(((wesgr"g"'tnreieacns*i(otrat(=(e*!iyyp'nheoe+"]etenn_sht']n"niiisf_]]laaa)te_nt="}''st_g._e:itEnstaf"iemmtsdct(-",,t_eydnfvdextelf"[dcu_llha)om'f-i"nmato:enc(ee{*ernp__,swnaf"-'n:"lt.uatef_G]aekaffrttm{2g"ain:p"=tE_antiicfiet'k0)(td=t[iNcptohllo:tne,}2}sIe"i!rtEraew)eenitr:0tDm{go]elRegdn:_,tn({-uEsl+en.eAaepegi}{1fA(en:Bs)Tt(pkaLnd)v2f_)nieruIipaetotpe.}-F:(drobOnagyhasaai0wIveak(Ngte:,d)g)t\5iL)ate'_hse:e:en'tE}[en[Dp,{"r:m")h)'_^Iafkr=s}itiIaRgco}"y{('pdidd-}eor")ap)aeteez/:n)ma:galaaA{t{ltese_:-s{el.h'pZapneF}tt]a{0fatnu"eo)gi-et)(l)med9_hvlpc_e_t})Llrca\i"}oaeo}\t)atan"nlidett)\edeee\}erb"n..a)a)t]mss('d"ei,")ddeoa'n),diidfefae[r'etnittlkee'y]s.,lotwheer(s)k.yreipslatchee('li'm,it

Using JSON (No dependencies) 🔗︎

Another version I’ve written uses JSON and moves the templates out of the Python script and into their own file:

iifilTDDDddimmrmoEAEEeefppopgMTSFffoomogPATArrriL__Uacwtnsappnlwmpwpplf_mttstnAFDLpuimels.eoiaaiaaoonatgTIITprtpwus=mwgtigtgggraijprl.ELR_lrhl_gek_ghneheegmnsaiob_EPy_ccrpdfiw(sps_ipae(otngaF=A_cou=o=taiinof)_oadnap_)nhggsI=Gpoprntrlgp.:dpg=eggp_liiL"EanerTtpsh(e.ewaeef.eliincE"._gtn_eeallp_inrtnspai_y=bmgCp/Dee(cmnguiapn(ia(_auni_=po=adA_ntoptegbrafntDdglfnpongoTttenls_.etoee=Aaetofa"rf"ecEosmtaiiPnh(w(Ttss(og_tit-s_pet=nsatf_nNAa_fe_ged/=t=lnefts='feo_d='i_mT(ma"eat(tonh=WiwnF=aNntaelpt"mNtscm.o(Tprl_eItpuoimela2poeupgtDriecLjaamp_npva/0ln_=rleEu/t_oEs[gat_lete2aefr.tNSeipn,o"epge_alex3tif_s(oT,fnatnpsaem"t=sa-el.cu'n_"gte'.a_gsp:el/m0(erobseDe{hnrlgde:loep2p,enslIxsn,t'oeasagxl-aattuRiles)ast:tgae0g'deig)suw")d"aeims5er(nt'tgwa(][{(np."_')tu)_}f"sd"lpgljd)sto.i,fpea.ese)eokmld)angI-ofa(r=deefg(eNtnaspT":n:ep_Fm"uaprc_adOplfgau{odge)lt:egendeef.s_e)eifsam:d_wna)udei_gu}l"dfnfltiafi=tPscuol"sa,tl[eu"g,t"_t]epstpfsap,ia-gatt8deglh"e_e*e})si_p"'cnia])a:fng.sofel{,o_owp:iwfaTne:gEdfreMio(sPc))_Lt.dA,raTetEtpa_el[Fma"IpcdLleeEa(s)t"ce"_"]f,}i.l".e-.:"'))str):


And the corresponding template file tmpl.md:

tddieatstlceer:a:idp$d$t{{ipetoavinget:enl_e$dm}{aodtreees}corpitpitoinosn}here,theskyisthelimit!

And corresponding data file examples.json:

{}"}"]d,pe""a{}spdgcae"e"""""gspstsrd:eca"ileo_rg:tupc"dielgosbep_[e"__lftd":llaaia:iihuot"nn.lne"tkk"t""Tw"",s::wi::"it:""tt""G2tehh{e0erttn2r"tte3",ppr-,ssi0::c2/-/D0gee6ixs"tachm.up"bl,.ec.ocmm"",

Next steps for Hugo auto-generated pages 🔗︎

You should now have a enough of an understanding of the current landscape to make the best choice for your circumstances. Despite Hugo not offering built-in support, there’s plenty of alternatives to programmatically generate pages. Whether you decide to write your own or use existing tools, there’s no bad option, choosing any of them will save you the time and frustration of manual creation.

Resources 🔗︎


Keep up with me!

Subscribe to get emails when I write new essays.

    We won't send you spam. Unsubscribe at any time.

    See Also