Is it possible to single-source files across Jekyll projects?

I have three Jekyll projects, and a set of HTML files that I sometimes need to use in all three. I don’t want to maintain three sets of identical files, so is it possible to call files in one project directory into a separate project directory?

For context, my three projects are:

  • an author website
  • a manuscript that will be my first book
  • a repo of all my poems (just to keep everything under version control; I’ll never serve this site)

I need to re-use the poems in the last project in the other two projects so I don’t have (in some cases) three copies of the same file.

I don’t see that Jekyll is set up for this, but wanted to reach out here.

Hi. There is no preferred Jekyll way to do this.

Be warned that duplication content on pages is bad for SEO scores unless you use a canonical meta tag to tell Google which is the original one.

Here are some ideas.

  • Put your content in gist as HTML, markdown or YAML. There is a plugin which can import content from a gist. It does this bother as dynamic content (embed a gist) and also downloads ststic content at build time for a fallback, which works for JS disabled and is SEO friendly
  • there was discussion in forums here recently on how to render an external github file in Jekyll like for gists. There seems no good solution yet but this might be a Jekyll builtin feature
  • Make a theme which you use on your 3 repos. Add your content as YAML data in config file or _data.yml directory of the the theme and use jekyll-data plugin. So any project using the theme can get the info on site.data or similar.
  • Similar above, but simpler, you can put your content as includes files in your theme. e.g. you can have a HTML or .md file for each poem in _includes. And another includes to render them all on one page. Then use that parent includes on the site.
  • A simple and direct approach is to just copy the content from github across repos. For example, say you have 3 repos that you mentioned. They can have their own unique content in page files or YAML files. Then you make a super repo. It can use git submodules to reference the 3 other modules as a directories. You can check a submodule into version control using a minimal commit reference so you don’t duplicate the entire repo.
  • If you don’t like that, you can have a shell script which runs at build time to clone the 3 repos into the current repo and then copy the appropriate files and directories into the current repo. Everything you download and copy to would be added to gitignore file so you don’t add duplicate content to version control

Finally consider if you want to go through the trouble of duplicating content across sites or if you can achieve your goal by just adding a anchor tag link between your sites. Click here to see my website of poems or Visit my website on my first book here

1 Like

Another option might be to use symbolic links with relative paths to link files/folders across projects. This assumes you’re on a unix-like system (macOS, Linux, Win10 WSL, etc) and can control the build setup.

1 Like

I thought about that as well but have seen warnings about it in context of Jekyll.

For example, when the symlink file has a relative path, then when it is moved into the output directory then it points to nothing.

Maybe a full symlink will work. ie ~/repos/myrepo/foo/bar.md rather than foo/bar.md

Also I don’t know if Jekyll process the contents of the symlink destination and move the result or will move the symlink first.

A symlink approach makes sense if you have cloned multiples ignored repos in the current repo or used submodules. a symlink saves having to duplicate content with a copy step.

Yea, symlinks can be tricky. My current understanding (at least for Jekyll 4):

  • Symlinks to directories work consistently – the entire directory tree is cloned.
  • Symlinks to static files are copied as symlinks, so relative-path symlinks are problematic if they point outside the source tree or if a web server doesn’t support them.
  • Symlinks to special files (Front-Matter files) are dereferenced and Liquid-processed to generate a new output file.
1 Like

Wow, thanks both of you for all these suggestions! I’m not familiar with gists, submodules, or symlinks, so I have a lot to read up on and test now.

Gist is probably the easy to reason about. You put some content on a gist file. Then use jekyll-gist plugin on one or more sites to pull in the content.

The problem is it doesn’t scale well like if you have 10 poems you need 10 gists. But maybe you can put them in a single multi file gist and then pull in each file in the gist.

I’d recommend experimenting with git modules and symlinks and such in non Jekyll throwaway project. And then in a Jekyll site where the structure matters.
So you can build up your understanding.

Good luck.

Guide to submodules I just put together if you are interested.

Finally got around to researching & testing submodules. Thanks again for this resource, and for pointing me to it! I’m having a few small issues implementing in Jekyll, but the biggest one is this: I can’t figure out how to access the submodule’s contents with Liquid.

I don’t know if I’m just not supplying the correct dot notation path, or if there’s a bigger problem with the relationship between the submodule & superproject. Based on the directory structure, I expect Liquid to access the poems at site.subPoems.poems, though I’ve tried every filepath variation I can think of with no luck. Any insight here?

I did add the submodule (it’s in the .gitmodules file with the correct name & URL), and I see the submodule both on GH & in my project tree in Atom. I’m also having no trouble pushing changes to each repo and seeing the submodule commits update in my superproject. But I can’t seem to interact with the submodule files.

I know the superproject is seeing them because of a different error—it’s reading the submodule content as though it’s in the root of the superproject (every filename is rendering as a link in the header, per Minima’s default behavior).

Here’s my test repo for experimenting with submodules:

Symlinks was the solution for me.

I created a separate directory for the poems, titled it _poems (to adhere to the Collections naming convention), and ran the following command for each project I wanted that directory available in:
ln -s path/to/poems path/to/project/collections
—so the symlink is to the entire directory.

I dragged & dropped the directories into Terminal, which gave me a full path from the MacOS home directory (/Users), but I didn’t specify the ~.

Everything is working great. Only two small issues:

  • live reload doesn’t work. If I make an edit in the symlinked directory (_poems), I have to stop the server & restart it to see the change.
    This is similar to using submodules, except I don’t have to run git add/git commit/git push/git submodule update in the submodule, and git add/git commit/git push in the superproject :raised_hands:
  • every file in _poems is included in the build. This is really an issue with the Collections functionality, but it’s irritating that it adds 100+ files to the repo when I might only be calling one or two in the code (some journals might consider this “previous publication”).

Can’t say I fully understand what you are trying to accomplish but I see you are using git.

I use git pull inside a shell script that moves stuff all around sub-directories, updates files with links, markdown, includes, etc. Then the script calls git add , git commit and git push.

Dealing with multiple directories on my local storage and multiple GitHub Repositories is time consuming. Because of that, and the fact I’m prone to errors, and lazy I guess, I just type “refresh.sh” at the command line and thousands of posts gets deployed in a few seconds (gotta love PCIe Gen 3x4 NVMe SSDs).

HTH