Updating Permalinks in Ghost

When I think about blogging, there is perhaps no more important feature or concern than impacts to SEO. It’s perhaps one of the biggest concerns many will likely experience when performing a migration to the Ghost blogging platform.

I recently migrated my personal blogs to this platform and share some insights into the installation process in case you want to give it a go.

As you might expect, it’s had it’s up’s and down’s, much like when I first got started with WordPress. Needless to say, I’ve been making my way through it over the past few days. I’ve learned a number of things, and one such thing pertains to permalinks.

A permalink is the link to an individual blog post.

Here is an example: https://perezbox.com/2014/12/ghost-blogging-for-the-future/

The challenge I had is that the content I previously had was setup to follow a very strict permalink structure:


This is how WordPress captures it, and this is what it looks like in your WordPress Dashboard:

In Ghost however, things are a bit different.

Configuring things like Permalinks might appear a bit daunting, and they technically are at first, but once you’ve figured it out, it’s easy moving forward. You find your Permalink option in Ghost under the Settings dashboard, but it leaves a lot to be desired:

By default, the structure is going to be /Year/Month/Day/Post Name. If you care about SEO then you know how disastrous this can be. (hint: the issue is the introduction of the Day value). That one value will likely break your previously cached and linked posts/pages, generating a number of 404’s and possibly a nightmare process of creating 301 redirects to account for the change.

Even with 301 redirects though you don’t address the issue you have with applications like Disqus that require the url structure per the default configuration. They have a process, but its more involved and I was feeling exceptionally lazy.

I wanted to modify the permalink structure within Ghost so as to have a seamless transition.

It’s in the Database!

For the life of me I couldn’t figure it out. I searched online, but as you might expect with a relatively young platform guidance can be hard to come by. There were a number of hacks. Modify core, do this, do that.. yet everyone and no one seemed to know the answer — at least it wasn’t shared. Turns out, it’s all in the database!

Specifically, it’s in the settings table, ID 13, you’ll see it set to: /:year/:month/:day/:slug

How To Update Settings Table

It might feel a bit daunting at first, but it’s very quick and painless to set it so that you set up the correct permalink structure. The good news is that once you’re live, it’s not like it’s something you configure and modify daily.

My mission: change /year/month/day/post to /year/month/post.

Reminder: I had to do this because of how my previous posts/pages had been indexed by Google and other search engines. The last thing I wanted was a series of 404’s or a long list of 301’s.

1. Navigate to the database. The default configuration of Ghost use Sqlite so it’s a bit different than MySql. You’re going to need to attach the database first:

`[root@server ~]# sqlite3 /[path to install]/content/data/ghost.db`

2. Next you might want to list out the tables to understand what tables are available:

`sqlite> .tables`

It will look like this on a clean install:

3. Familiarize yourself with how to look at the database in terminal. You could configure a GUI but that sounds complicated, so here is what to do:

`sqlite> .show`

It will look like this:

4. You’re going to want to configure the databse output to look like something that makes sense (so that your eyes can easily understand what it’s showing).

Focus on:

> **headers | mode | width**

You can use these options:

`sqlite> .headers on`

`sqlite> .mode column`

`sqlite> .width 10 25 25`

5. Now output the ID | KEY | Value columns:

`sqlite> select id, key, value from settings;`

This will output something like the following:

6. Now it’s time to update ID 13 with the right permalink structure.

`UPDATE SETTINGS SET VALUE = '/:year/:month/:slug' WHERE ID=13;`

If you look at your table now it’ll look like this:

6. Now you have to be sure to restart your Ghost instance, if you followed my instructions then you can use pm2 to restart your instance:

Exit the databse:

`sqlite> .exit`

And restart the Ghost instance:

`[root@server ~]# pm2 restart Ghost`

Depending on the number of instances you have running it’ll look something like:

Congrats, now you’re all situated. As long as you retain the same domain, there shouldn’t be any issues when you go live and your permalinks should all align nicely.

Happy blogging!


  1. Chris Blunt on January 8, 2016 at 11:29 pm

    Thank you for this great write up – really helpful for me migrating our content to Ghost. I needed permalinks in a ‘domain.com/blog/post-title/’ format, which can be done setting the permalink to ‘/blog/:slug/’.

    There’s also a handy list of tokens that can be used on this Github issue (https://github.com/TryGhost/Ghost/issues/1631).

  2. 袁源 on January 12, 2016 at 12:52 am

    I changed from /:slug/ to /post/:slug/ but it doesn’t work

  3. 袁源 on January 12, 2016 at 12:54 am

    I changed from /:slug/ to /post/:slug/ but it doesn’t work. The links in the front page are changed, but click on each of them returns 404

  4. runmygeek on May 25, 2016 at 6:02 am

    there is an issue with last version of ghost
    you must add a final slash to the permalink :
    `UPDATE SETTINGS SET VALUE = ‘/:year/:month/:slug/’ WHERE ID=13;`

    Thanks for your post it was helpful

  5. Micheal Ethan on July 20, 2016 at 12:22 am

    Every Blog post that you write and publish using Ghost can be accessed from a URL. Ghost generates URL based on the Title of your Blog post. Let’s say the title of one of your posts is “Making still
    photography more innovative.”. By default, Ghost will create its URL by joining the words in the title with dashes.Although it’s nice to have URLs which look similar to the post titles, sometimes you may want to change them.

  6. Paul Davis on July 21, 2016 at 4:52 pm

    Thank you so much for this! Made migrating from my Jekyll blog a little easier.

    Just to echo @runmygeek:disqus, you do need that final slash at the end.

    It was also on line 12 for me, Ghost version 0.8.0. `email` is now missing. https://github.com/TryGhost/Ghost/pull/5306

Leave a Comment