# Move topics from one Discourse instance to another

**URL:** https://meta.discourse.org/t/move-topics-from-one-discourse-instance-to-another/38930
**Category:** Self-Hosting
**Tags:** how-to
**Created:** [February 2, 2016, 10:11pm UTC](https://meta.discourse.org/t/move-topics-from-one-discourse-instance-to-another/38930 "2016-02-02T22:11:02Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![Discourse](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/discourse/32/148734_2.png) [@Discourse](https://meta.discourse.org/u/Discourse)
#### Post date: [February 2, 2016, 10:11pm UTC](https://meta.discourse.org/t/move-topics-from-one-discourse-instance-to-another/38930/1 "2016-02-02T22:11:02Z")

</div>

Need to move some stuff from one instance of Discourse to another?

There is a command line tool to export a topic, a set of topics, or an entire category, and another to import them in at the other end.

### Topic Export/Import

- one or more topics and their replies
- the users who posted in the topic

### Category Export/Import

- the category and all its subcategories
- its security settings
- custom groups mentioned in the security settings
  - ⚠ if any of the groups have ‘membership requests’ enabled, it will crash. Turn this off _before_ the export

- all topics and posts in the category and subcategories
- all users who posted, and assigns them to the groups

## Begin: Identify the IDs

First, identify the ID(s) of the =Export= that you wish to export. You’ll find this at the end of the URL used to access it.

- `https://meta.discourse.org/t/how-to-contribute-to-discourse/53797`

- `https://meta.discourse.org/t/how-to-contribute-to-discourse/53797/12`  
(in this case you are in the middle of a topic - grab the first number)

- `https://meta.discourse.org/c/howto/faq/4`

Category or Topic ID(s)

### Multiple topics

You can select more than one topic by adding IDs separated by a space; this works in the field above (I don’t think that this works for categories though):

- `53797 200943 124096`

## Run the Export Script

The tool can be run as a root user inside the container:

```plaintext
cd /var/discourse
./launcher enter app

```

Run this command:

```plaintext
discourse export_=Export= =ID=

```

The output should look something like this:

> Starting export of =Export=…
> 
> Where are the new users all coming from?  
> Export saved to =Export=-export-2021-08-27-015437.json
> 
> Done

## Move the Exported File

The exported .json file needs to be moved from the inside of the application container where you did the export to the inside of the container of the receiving instance. This takes a few steps.

### Copy it to the ‘outside’

Exit the container if you haven’t already

```plaintext
exit

```

You should now have a prompt like this:

> root@yourserver:/var/discourse

Use docker to copy the file out of the container (you can’t move it I don’t think)

```plaintext
docker cp app:/var/www/discourse/=FileName= .

```

### Move it to the other instance

This is beyond the scope of this guide, but this might help you get there:

> **[How to Transfer Files from Server to Server (3 Ways in 2026)](https://www.ubackup.com/windows-server/transfer-files-from-server-to-server.html)**
>
> You can choose to transfer files from server to server manually with FTP or SCP, or directly use powerful sync software - AOMEI Backupper to make it automatically.

### Copy it into the container in the receiving instance

SSH into your receiving instance as root and get to the Discourse directory:

```plaintext
cd /var/discourse

```

Use docker once again to copy the file into the other container

```plaintext
docker cp =FileName= app:/var/www/discourse

```

## Import the Content

Enter the container in the receiving instance:

```plaintext
./launcher enter app

```

Run the import script

```plaintext
discourse import_=Export= =FileName=

```

🍰 Done!

You might need to tidy up some loose ends, but hopefully, it should all be done.

## Advanced Tips

### Missing Ruby Gem

When doing a complex category import, my instance was missing the ‘Listen’ Ruby.  
This was solved by doing this: (using the Discourse user inside the container)

```plaintext
./launcher enter app
su discourse
bundle config --delete without
bundle config --delete with
bundle install
exit
exit

```

This broke the rails console, necessitating a rebuild afterwards

```plaintext
./launcher rebuild app

```

### Multisite

In a multisite environment, use the RAILS\_DB env variable.

```plaintext
RAILS_DB=xxxmoves discourse export_=Export= =ID=
RAILS_DB=dancerehab discourse import_=Export= =FileName=

```

Please report bugs in the #Contribute > Bug category, and request enhancements in the #Contribute > Feature category.

* * *

### Related Topics

> [@Merge two Discourse sites into one](https://meta.discourse.org/t/how-to-merge-two-discourse-sites/95435):
>
> If you have two Discourse sites that you wish were one, this guide is for you. There’s a tool called [discourse\_merger](https://github.com/discourse/discourse/blob/main/script/bulk_import/discourse_merger.rb) that can take one Discourse site and merge it into another. Prereqs This is not an easy task, and should be treated like any other migration to Discourse. You will not be running discourse\_merger on a live production site. You will perform the merge in another environment where you can review the output before moving the result to production. Copy vs Merge Almost everythin…

* * *

_Last Reviewed by @SaraDev on 2022-07-13T00:00:00Z_

 

> Last edited by @hugh 2024-05-29T06:25:11Z
> 
> > **Check document**
> >
> > Perform check on document:

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [April 26, 2024, 10:04pm UTC](https://meta.discourse.org/t/move-topics-from-one-discourse-instance-to-another/38930/59 "2024-04-26T22:04:31Z")

</div>

I’m about to have a crack at this again.

Is there an easy way to migrate the relevant uploads along with the Topics?

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [April 26, 2024, 10:37pm UTC](https://meta.discourse.org/t/move-topics-from-one-discourse-instance-to-another/38930/60 "2024-04-26T22:37:52Z")

</div>

> [@nathank](#):
>
> Is there an easy way to migrate the relevant uploads along with the Topics?

Not really. A thing that mostly works is if you get all of those uploads and paste the URL of the original in to any post on the site you’re moving to, then what _should_ happen is that those uploads will get created with the same SHA and it Just Works.

So you’d do the thing that converts the stuff in the post to the URL to get those URLs. (I can never quite remember how to do that, so I have to figure it out every time).

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [April 27, 2024, 5:28am UTC](https://meta.discourse.org/t/move-topics-from-one-discourse-instance-to-another/38930/61 "2024-04-27T05:28:08Z")

</div>

Hmmm - I remain a bit confused by that. Are you saying that this will work?

1. Grab all of the upload files from the first site
  - how?

2. Drop them into a single topic
3. They will generate the same relative link as they had in the old site and magic!

Or did you mean this?

1. Grab all of the absolute URLs in your categories of interest from the old site
2. Paste these into a Topic
3. They will all be downloaded to the new site with the same SHA and the existing links will all work like magic

Or something else entirely?

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [April 27, 2024, 8:17am UTC](https://meta.discourse.org/t/move-topics-from-one-discourse-instance-to-another/38930/62 "2024-04-27T08:17:40Z")

</div>

I think either of those should work. However you can get those images to the new site, they should generate the same sha so that will magically make the existing links in the topics work.

Maybe you could do something like

```plaintext
cat_id=123
Topic.where(category_id: cat_id).each do| t|
  Post.where(topic_id: t.id) do |p|
      p.cooked.match(image url)....
         puts(the match) 

```

And I think if you do that and paste those links into a post anywhere on your site it should download all of those images to local and make the same sha, so then those links. You can try a couple by hand to see.

It’s the middle of the night. Your mileage may vary.

---

<div class="post-metadata">

### Author: ![Master](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/master/32/383814_2.png) [@Master](https://meta.discourse.org/u/Master)
#### Post date: [May 8, 2024, 12:36am UTC](https://meta.discourse.org/t/move-topics-from-one-discourse-instance-to-another/38930/63 "2024-05-08T00:36:55Z")

</div>

Hello, I’m not sure if this tutorial is what I want to do, but raise the question here.

If I install discourse on a server, but due to growth I need to migrate to a more powerful one, are these the steps?

What happens, for example, with the backup option? Can’t I do it, install Discourse on another server and then restore the backup copy of the other instance from that option?

I await your clarification, since I want to know how to migrate when I need to and not lose the work I have been doing recently.

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [May 8, 2024, 1:18am UTC](https://meta.discourse.org/t/move-topics-from-one-discourse-instance-to-another/38930/64 "2024-05-08T01:18:11Z")

</div>

No. To move to a bigger server a simple backup and restore is all that’s needed. You can also [Move a Discourse site to another VPS with rsync](https://meta.discourse.org/t/move-a-discourse-site-to-another-vps-with-rsync/43812)

---

<div class="post-metadata">

### Author: ![tobiaseigen](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tobiaseigen/32/539204_2.png) [@tobiaseigen](https://meta.discourse.org/u/tobiaseigen)
#### Post date: [August 20, 2026, 7:16pm UTC](https://meta.discourse.org/t/move-topics-from-one-discourse-instance-to-another/38930/65 "2026-08-20T19:16:58Z")

</div>

I’ve been wanting to solve the upload migration problem for just about forever, and now with AI chatbot help have gotten there. Sharing my notes for those who follow! Jay’s [post above](https://meta.discourse.org/t/move-topics-from-one-discourse-instance-to-another/38930/62) contained the special sauce needed to get me started so thanks for that.

My first pass at this worked exactly as Jay predicted. If you create a list of urls to the images on the site you are moving from and paste that into a post on your new site, they will be downloaded. `Download remote images to local` must be enabled for this to work.

My AI chatbot created a script for that which I’ll share here for future travelers.

> **Summary**
>
> Run this in the rails console:
> 
> ```plaintext
> topic = Topic.find(=TOPIC_ID=)
> posts = Post.where(topic_id: topic.id)
> urls = []
> 
> posts.each do |p|
> UploadReference.where(target: p).each do |ref|
> urls << "=SOURCE_URL=#{ref.upload.url}"
> end
> end
> 
> puts urls.uniq.join("\n")
> puts "\nTotal: #{urls.uniq.count} upload(s)"
> 
> ```
> 
> > 💡 **Moving a whole category instead?** Replace the first two lines with:
> > 
> > ```plaintext
> > topic_ids = Topic.where(category_id: =TOPIC_ID=).pluck(:id)
> > posts = Post.where(topic_id: topic_ids)
> > 
> > ```
> > 
> > In this case =TOPIC\_ID= is your category ID, found at the end of its URL in Admin → Categories.

However for me that ended up not being good enough because I also have PDFs which do not get downloaded to local automatically.

So I had my chatbot write me a python script to migrate the uploads. It works quite well so happy to share it as well. If you’d like to try it or have feedback, [here’s the repo](https://git.digitallysovereign.org/tobias/discourse-upload-migrator).

I also had my chatbot write me a more complete runbook on moving topics or categories, which is up on [my discourse](https://digitallysovereign.org/t/move-topics-or-categories-between-discourse-instances/742?u=tobias).
