Migrating to Hugo - Keep original urls but keep files under content/posts

Hey all
I have an existing blog (Ghost) and I decided to move it to Hugo. One important thing is that I want to keep the existing URLs of my posts.

I read almost everything under “Content management” and “URL Management”. This is my current structure of posts on Hugo:

content
   posts
      2018
        - my-first-post.md
        - my-second-post.md
        - my-third-post.md

In each post I used the url param in front matter with the value being the existing URL of each post. I run the site and everything looks great (URL wise they are the same as my current).

Today I ran hugo and I took a look at the public folder and I was confused. After try and error I think I understand. The public folder looks like this:

assets/
categories/
...(hugo "default" stuff)
posts -> has index.html
myfirst-post/
mysecond-post/
mythird-post/

So the public folder contain my posts at the top level directory, and not under posts/2018/.... And the folders are named as the url param I added in front matter. I understand this and I see this is by design (correct me if I’m wrong!)

My question is: How can I use my existing blog post URLs, but keep the posts organized (inside posts) when I publish the site? Ultimately I wanted them inside posts/year/… but override the url.

I also tried using permalinks like so:

permalinks:
  posts: /:slug

And then using slug instead of url in front matter of each post, but that also puts the files outside posts when I publish the site. The same if I use posts: /:filename.

Thanks!

Take a look at the documentation for aliases. I converted a large blog from MovableType this way without breaking any of my old URLs.

-j

Hey, thanks for your help! I tried briefly with Aliases after seeing other posts here… but I still have the top-level folders with the redirect html file… I guess there’s no way around them? I don’t have many posts but I will have, at least 10 of these folder hanging around… not so great =/

Did you have the same in your migration? Since you mentioned it was a large blog I wonder if you had the same issue? I saw the Customize section in the docs about having a template alias but now sure that can help?

Assuming you want the page to be at /posts/2018/my-first-post/index.html, try this:

  1. Remove the url front matter setting.
  2. Use a custom permalinks config for posts:
permalinks:
  posts: /posts/:year/:filename

Hey @moorereason,

I want the posts to not have the folder structure in the URL. I would like the URL to be like this: mysite.com/myfirst-post where myfirst-post is the URL of my existing blog post. So no “subfolder” in the URL at all.

As @jgreely mentioned above, I can use aliases but I still have the redirect .html files published at the root of my site… not sure I can avoid those using Hugo. I know I can work-around the redirects via DNS and whatnot… but would like to see if I can do something with Hugo first.

@maxjpg, sorry I misunderstood; I thought you just wanted to preserve the old URLs for existing posts, and use a standard organization for new posts. If you want to have a URL like /myfirst-post while only storing the file in content/posts/myfirst-post/index.html, you’ll have to implement it in your web server configuration; Hugo just generates a tree of files, it can’t tell your web server how to get from a virtual /A to a physical content/posts/2008/12/15/A/index.html.

For instance, in Nginx, you could use try_files to search sub-directories for any top-level post names:

location / {
    try_files $uri 2008/$uri/ 2009/$uri/ $2010/$uri/ ...;
}

If you wanted to get fancy, you could write a custom output format for your server’s redirect config and have Hugo generate a complete set of /A -> wherever/A/ mappings that would be slightly faster at runtime.

-j

Could you clarify what structure you want Hugo to produce for you?

This is correct, and is expected.

What is your existing blog post URL?

So do you want it under yoursite.com/posts/2018/post1/ as mentioned in my second quote snippet of your post above, in bold; or do you want it in yoursite.com/post1/?

Given the following content structure:

content/posts/
    - post1.md
    - post2.md
    - post3.md 

Hugo by default will render:

yoursite.com/posts/post1/
yoursite.com/posts/post2/
yoursite.com/posts/post3/

What URL do you want these pages to be published at?


If you want

yoursite.com/post1/ AND yoursite.com/posts/post1/

Then you use aliases and point one to the other, ie something like:

---
# posts/post1.md
title: Post 1
aliases:
    - /post1/
---

Which will give you yoursite.com/post1/ which will redirect to yoursite.com/posts/post1/

If you want yoursite.com/post1/ ONLY, then your options are to

  1. define the url on each post, ie:
---
# posts/post1.md
title: Post 1
url: /post1/
---

OR

  1. configure the permalinks in config.toml
[permalinks]
  posts = "/:slug/" # or whatever

Either of these should give you yoursite.com/post1/

1 Like

Yeah @jgreely so makes sense that if I want this way I will need to handle this in the server. Thanks for your help!

@pointyfar I want my blog posts to not have the subfolders in the final URL. For example, one of my posts today (in Ghost): https://blog.joaograssi.com/asp-net-core-integration-tests-with-docker-compose-azure-pipelines.

I figured it out that to have the same URL as above, I need either the url in front matter, or change the permalinks.

My actual question was how I could do this, but still have the “output” public folder organized inside the content/posts folder.

But I understand more… it’s not a concern of Hugo to do this, but more to configure on the server.

A general question now: I will use the ‘url’ in front matter for the existing posts I have, and use the Hugo structure for the new ones. Just thinking… if I move another day to another static generator or whatever, what is the best to keep? All the blogs I follow, they don’t use the pattern like /posts/year/month or any other combination. It’s just all at the “root” like mine example above.