Understanding and improving Nextcloud Previews

NextCloudPi‘s target audience is domestic hosters and one of the use cases that attracts users is to self-host their own picture collection.

The main complaint for such users is that gallery is too slow. When you open the gallery previews are generated on the fly which affects responsiveness. Once they are generated, the next time it will load much faster.

The current solution is to generate the previews offline through a cron job using the Preview Generator App so that they are ready to be fetched when we open the Gallery.

Even when using this App browsing our pictures is usually very slow. This happens typically for the following reasons

  • Lack of computing power. SBCs are not very powerful.
  • Misconfigured preview sizes (and lack of documentation thereof).

Even using the Preview Generator, it can take days or even weeks on a Raspberry Pi to generate the previews for a big collection which throws many people off.

Another complaint is that too many previews are generated so often the previews folder takes even more space that the pictures themselves.

The most obvious low hanging fruit to try to deal with this issue is noticing the fact that even though our systems are multi processor, only one CPU is used to generate the previews so there are plenty unutilized resources available that are not being used.

First, let’s take a quick look at the Nextcloud Previews system.

How previews work

Every time we upload an image two previews are generated

  • Small 32×32 preview. This is the icon in the Files list.
  • Max preview. This is the big picture that shows in the browser when you click on it.

The Max preview size defaults to 4096×4096, and can be configured with

occ config:system:set preview_max_x --value 2048
occ config:system:set preview_max_y --value 2048

This produces

root@293626d9121d:/var/www/nextcloud# ls -R data/appdata_ocn7c0nrnm7u/preview/*
1365-2048-max.jpg  256-256-crop.jpg

There are other previews that are not generated by default but are used by other parts of Nextcloud. These will be generated on the fly unless they are pregenerated with the App.

  • The Gallery App requests (js/thumbnail.js)
    • 400×200 -> 384×256 / 256×384 (**) for regular thumbnails.
    • 200×200 -> 256×171 / 171×256 for folder thumbnails, which shows the first four square thumbnails of the directory.
  • The Files App in grid view mode requests (js/filelist.js)
    • 250×250 -> 256×256

(*) it requests 400×200 but the backend rounds it up to powers of two -> 384×256. These are examples only.

(**) depending on photo orientation

How the Preview Generator works

We can see that we need a properly configured Preview Generator or we might be generating previews that are useless since they are not going to be used.

By default the App generates all possible sizes from 32×32 to Max which is both a waste of CPU and space since as we just saw many of those won’t be used.

root@293626d9121d:/var/www/nextcloud# ls -R data/appdata_ocn7c0nrnm7u/preview/*
1024-1024-crop.jpg 171-256.jpg 256-384.jpg 2731-4096-max.jpg
64-64-crop.jpg 683-1024.jpg 1024-1536.jpg 256-256-crop.jpg 
2731-2731-crop.jpg43-64.jpg 64-96.jpg

If we don’t want this behavior, the App allows us to configure what sizes we want to generate, but it is not documented anywhere what sizes are really needed unless you dig in the code. To configure this setting

occ config:app:set previewgenerator squareSizes --value="32 256"
occ config:app:set previewgenerator widthSizes  --value="256 384"
occ config:app:set previewgenerator heightSizes --value="256"

So we end up with either people complaining that the previews take more GiB than the actual photos or people naively trying different sizes assuming that they will be used when they will most likely not be.

Recommended configuration

For the reasons stated above, I recommend the following settings for a SBC

occ config:app:set previewgenerator squareSizes --value="32 256"
occ config:app:set previewgenerator widthSizes  --value="256 384"
occ config:app:set previewgenerator heightSizes --value="256"
occ config:system:set preview_max_x --value 2048
occ config:system:set preview_max_y --value 2048
occ config:system:set jpeg_quality --value 60
occ config:app:set preview jpeg_quality --value="60"

In my opinion these should be the default settings for the Preview Generator App.

root@293626d9121d:/var/www/nextcloud# ls -R data/appdata_ocn7c0nrnm7u/preview/*
1365-2048-max.jpg  171-256.jpg  256-256-crop.jpg  256-384.jpg  64-64-crop.jpg

Just configuring the Preview Generator properly results in a 4x speed up and saves lots of wasted space (see results below).


In order to try to find a way of using our CPUs more efficiently and to improve performance on low end devices, I forked Nextcloud and the Previews Generator App to create a Proof of Concept implementation that I could run some tests on.

We don’t need very good quality using computationally expensive filters for the small thumbnails, maybe only for the Max preview, so the proposal plays with scaling without interpolation and parallel generation to try to achieve better results.

Using these modifications I was able to achieve a 5x speed up in a 4 core Raspberry Pi and a 10x speed up in my 16 core PC while retaining good image quality.

If we compare with an unconfigured Preview Generator the gain is 20x for the Raspberry Pi and 50x for the PC (see Github link).

You can check more details about these benchmark results on Github.

Author: nachoparker

Humbly sharing things that I find useful [ github dockerhub ]


  1. “Max preview. This is the big picture that shows in the browser when you click on it.”
    ==>> Do you mean that when playing a slide show, the pictures shown are NOT the actual pictures but generated ones ????
    If so, what a wast of power and space.
    And I understand why, with fiber connection at home (on a Rock 64), it take ages to display pictures when I’m away.

      1. Can I disable max previews so that it shows the original picture? Would safe a lot of space and generation time…

  2. This is great, thanks so much for this and the work you’ve done. I will give it a try on my docker container, hopefully it will speed it up as well.

  3. Let us hope that Rullzer will include these enhancements in the official app. πŸ™‚

    Just one thought. When running php-fpm, then the server does spawn several threads to generate thumbnails. Still extremely slow.

    1. only when you browse the gallery since there are several requests in parallel, but the preview generator only uses one thread (before my changes).

  4. hello,

    where and how can i change the directorie’s to preview, not every directory should be shown as a preview or only 2 to 3 specific directories would be in this site !? thanks for your help

  5. I am not quite sure I understand the commands above right πŸ™

    First of all, should I use the commands in the two boxes in the “How the Preview Generator works” section or are those just explanatory?
    Second of all, when I ssh into my FreeNAS nextcloud jail and try to run occ config:app:set previewgenerator squareSizes –value=”32 256″ I get an error occ: Command not found.

    What am I doing wrong? Thanks in advance for your help!

    1. In your ssh session to Nextcloud jail:
      cd /usr/local/www/nextcloud
      run all command like
      sudo -u www php occ config:app:set previewgenerator squareSizes –value=”32 256β€³

  6. Thank you for your wonderful post. However there seems to be another bug which makes Nextcloud super slow: it is trying to make previews of mp3-s which takes minutes for just one mp3. I have a fresh Nextcloudpi setup (on a Raspi 3), uploaded a directory with a few mp3-s using webdav, and then visit that directory with the Nextcloud ios app without clicking on any file. These lines appear in /var/log/apache2/nc-access.log: – – [21/Jul/2019:10:34:34 +0100] “GET /index.php/core/preview.png?file=body%20mind%20soul/bl%20purpose.mp3&x=576&y=768&a=1&mode=cover HTTP/2.0” 404 0 “-” “Mozilla/5.0 (iOS) Nextcloud-iOS/2.23.7” ~126/126258422~ – – [21/Jul/2019:10:34:34 +0100] “GET /index.php/core/preview.png?file=body%20mind%20soul/bl%20ml%201of2.mp3&x=576&y=768&a=1&mode=cover HTTP/2.0” 404 0 “-” “Mozilla/5.0 (iOS) Nextcloud-iOS/2.23.7” ~126/126590957~ – – [21/Jul/2019:10:34:34 +0100] “GET /index.php/core/preview.png?file=body%20mind%20soul/bl%20med.mp3&x=576&y=768&a=1&mode=cover HTTP/2.0” 404 0 “-” “Mozilla/5.0 (iOS) Nextcloud-iOS/2.23.7” ~126/126603509~ – – [21/Jul/2019:10:34:34 +0100] “GET /index.php/core/preview.png?file=body%20mind%20soul/bl%20law%20of%20life.mp3&x=576&y=768&a=1&mode=cover HTTP/2.0” 404 0 “-” “Mozilla/5.0 (iOS) Nextcloud-iOS/2.23.7” ~126/126610499~

    ~126/126610499~ means that it ran 126 seconds (and 126610499 us to be precise)

  7. Hello!
    Is it possible to generate previews for videos like .mp4 or even .gif?
    Im using the cronjob from the nextcloudpi webpanel, pictures are no problem its really smooth with my rpi 4.

    In my gallery i got 4 folders filled with pictures. But there should be 3 more folders filled with videos and gifs.
    One of the working gallery folders got 1 gif data and is even pre generated. I just cant understand why the other folders aren’t pre generated.

    Would be nice if someone could help me, i saw that this site is really active in the comments!

    Ty and have a nice day!

  8. Very Cool! Thanks, after setting app as here written and “reset” the preview cache, there are following files were generated:
    total 444
    drwxrwxr-x 2 www-data www-data 4096 Jul 24 21:26 .
    drwxrwxr-x 13403 www-data www-data 274432 Jul 25 09:03 ..
    -rw-rw-r– 1 www-data www-data 128154 Jul 24 21:26 1080-1920-max.jpg
    -rw-rw-r– 1 www-data www-data 6133 Jul 24 21:26 144-256.jpg
    -rw-rw-r– 1 www-data www-data 9542 Jul 24 21:26 256-256-crop.jpg
    -rw-rw-r– 1 www-data www-data 14211 Jul 24 21:26 256-455.jpg
    -rw-rw-r– 1 www-data www-data 1618 Jul 24 21:26 64-64-crop.jpg

    OLD Preview Folder is bigger and has less files in it:
    total 1228
    drwxr-xr-x 2 www-data www-data 4096 Jan 14 2019 .
    drwxrwxr-x 39159 www-data www-data 933888 Jul 24 14:00 ..
    -rw-r–r– 1 www-data www-data 309785 Jan 14 2019 1080-1920-max.jpg
    -rw-r–r– 1 www-data www-data 1279 Jan 14 2019 32-32-crop.jpg

  9. Thanks so much for tracking down why Nextcloud can sometimes be so very painfully slow an SBC’s. SBC’s being constrained hardware will indeed reveal where the obvious wastages and bottlenecks and inefficiencies are. Thanks for all your awesome contributions, NachoParker!

  10. Thanks, very insightful!

    I did notice that on my Nextcloud (not NextCloudPi) instance, 1024×1024 thumbs are requested for the 32×32 images in the files list. So with your recommended settings, it’s still creating 1024×1024 thumbs on the fly. Is this configurable somewhere? Or is this different for NextCloudPi vs regular Nextcloud? In any case with 1024 added to the `squareSizes` setting, no thumbs are created on the fly anymore so that’s great!

  11. Thanks a lot man. I’ve always had the impression that nextcloud is creating previews when a folder is opened the first time, even though the preview generate plugin was installed. But i’ve never hat time to look into it.

    Now everything loads perfectly smooth!!!!

    Did you fill out but reports about the different picture sizes? I’ve only could find the push request for the parallel preview generation. Since a lot of users would assume that the preview generation plugin does everything correctly, most would never get the idea to look further into it.

  12. 291/5000
    Thank you very much for this guide. My Nextcloud works on a selfmade NAS with Celeron processor, where the preview generation takes ages with default settings. These settings have greatly accelerated the creation of the previews and, above all, the retrieval of images from the phone or web access.

  13. I just noticed it was the previews folder that had filled up my drive, and searching for a solution lead me right here. Thanks for the write-up! One follow-up: I want to start over from scratch, can I just delete that preview folder, or what?

  14. For nc-previews-auto, it says, “You can specify a nightly duration in minutes, or 0”
    How can I determine what time it begins the process nightly? I have other backups and need to stagger these jobs.

  15. Is this already rolling somewhere on github for nextcloud? I assume that nobody will have anything against those changes so can you process it somehow? All of us commenting this post are waiting for your changes πŸ™‚ It would be also best if there would be an option to set up the core number for parallel processing in the administrator UI.

  16. Impressive improvements!
    This should be part of the default configuration of Nextcloud. The current default makes the gallery barely unusable also on standard PCs.

    Thank you!

  17. Excellent article! Could anyone reproduce the steps to incorporate the “Preview Generator changes” in an automated way? Or does it have to be done by hand? Thank you in advance,

  18. Hello,
    Been searching for a way to increase the delay time between slideshow images. I discovered how to accomplish that when viewing slideshow from the gallery , but the images are not as large as the images in photo slideshow. If I could only merge the best characteristics of both photo slideshow and gallery slideshow I would be happy (until the next puzzle to solve comes my way).

  19. I’ve checked (actually debugged) sources of last stable Nextcloud 17.0.2, of lib/private/Preview/Generator.php and found these lines in calculateSize() method:
    if ($height !== $maxHeight && $width !== $maxWidth) {
    * Scale to the nearest power of four
    $pow4height = 4 ** ceil(log($height) / log(4));
    $pow4width = 4 ** ceil(log($width) / log(4));

    // Minimum size is 64
    $pow4height = max($pow4height, 64);
    $pow4width = max($pow4width, 64);

    So actually only size of power of 4 make sense: 64, 256, 1024, 4096
    Ans since we don’t want 4096 because it’s too big and since Android app and web app on my browser request minimum 256×256 images and 1024 width / 1024 height in full page previewI’d recommend set this:

    occ config:app:set previewgenerator squareSizes –value=”256 1024″
    occ config:app:set previewgenerator widthSizes –value=”256 1024″
    occ config:app:set previewgenerator heightSizes –value=”256 1024″

    Anyway, all other sizes excpet power of foure in these settings doesn’t make sense

  20. Hello, thanks for pointing me this topic.
    In Nextcloud 16.x I use this previewgenerator configuration to produce exactly the same preview files as they were created from Nextcloud Files App, Nextcloud Gallery and Android Nextcloud App itself:

    occ config:app:set previewgenerator squareSizes –value=”256 1024″
    occ config:app:set previewgenerator widthSizes –value=”384 2048″
    occ config:app:set previewgenerator heightSizes –value=”256 2048″
    occ config:system:set preview_max_x –value 2048
    occ config:system:set preview_max_y –value 2048

    Best regards,

  21. Is there a way to just keep a certain preview and delete the original file after generating the preview? The scenario: Various users upload their pictures for sharing but storage capacities are limited and viewing the e. g. 1024px version in the browser is perfectly fine.

  22. Is there a different method when MariaDB is used as the default DB?

    I would like to see the preview just use 32 / 64 for the icon previews and skip all other previews.

    If the user clicks to view the full photo it should show the original size. Does anyone know how would that be achieved?

    This preview generation issue really seems the Achilles heel of NC in my opinion. To waste an extra 10-25%+ of storage space on preview generation, let alone the time to create the files seems very wasteful.

  23. When you click an image in Files list the image file is immediately downloaded. Can this be changed so the image big preview (slideshow) is opened, just like you click an image in Photos?

    1. I’m not 100% sure, but I tried to test it a bit and it seemed like it also uses 256 in my case.

      I deleted all previews and opened a picture folder in my Android Nextcloud app, afterwards there were previews for the size 256 present in the previews folder.

  24. This is great info but different for me unfortunately. I had the time (and motivation) to dive into the server access log to see what’s being request and here’s what I found for my three platforms/uses:

    Chrome Desktop browser
    β€’ Photo app tiles
    o x=256 y=256
    β€’ File listing thumbnail
    o x=625 y=625
    β€’ Click image, blown up
    o x=1536 y=864
    β€’ Activities thumbnails
    o x=150 y=150

    Chrome Android browser
    β€’ Folder listing thumbnails
    o x=1000 y=1000 (yes, this is correct. The thumbnail is higher res than the blown up image)
    β€’ Click image, blown up
    o x=360 y=760 (yes, this is correct. The thumbnail is higher res than the blown up image)

    Nextcloud Android app
    β€’ Folder listing thumbnails. This request is different, goes to a thumbnail URL. All other requests go to a preview URL.
    o x=512 y=512
    β€’ Click image, blown up
    o x=1440 y=2706
    β€’ Activities thumbnails
    o x=150 y=150

    Now to translate this into the necessary OCC commands!

  25. So after the above comments, I wiped out the preview folder and went through each of the above (Chrome Desktop, Chrome Mobile, Android NextCloud) and scrolled through a few page worth of photos. Then I did a ‘find . -name “*.jpg” in the preview folder and exported all the filenames into excel, consolidated, and the results are as follows:
    More to follow as I work on this.

  26. And here we are, after limited preview sizes to 1920×1080 in the config.php. Regenerated previews (manually, my browsing photos)
    121 256
    144 256
    192 256
    240 240
    256 121
    256 144
    256 192
    256 193
    256 256
    352 240
    510 1080
    511 1080
    512 512
    512 1080
    525 1080
    540 960
    608 608
    608 1080
    640 480
    768 1024
    810 810
    810 1080
    880 880
    960 540
    960 544
    1000 1000
    1024 1024
    1080 810
    1433 1080
    1440 1080
    1860 880
    1920 909
    1920 1080

    Now to translate into occ commands. Apologies for the several posts in a row, just wanted to share the progress with you all for anyone interested.

  27. So I disabled PreviewGenerator and did some testing by logging into my different devices to see what files would end up being generated and it is ALL over the board. The requests are mostly uniform (depending on devices and app and function) but what the backend actually does with those requests varies. So as I stated on my previous post, to put it concisely, the following is what is requested:
    Android NC app: 512×512, 1440×2706, 150×150
    Windows Chrome: 256×256, 625×625, 1536×864, 150×150
    Android Chrome: 1000×1000, 360×760
    So there are 9 variants of what is requested from the web server.

    NC then translates that into actual file generation, and the image sizes vary wildly. For example, with 480 preview files generated, this is the breakdown:
    Max sizes:
    352 240 4
    510 1080 1
    511 1080 9
    512 1080 3
    525 1080 2
    540 960 5
    608 1080 10
    640 480 1
    810 1080 60
    960 540 1
    960 544 1
    1000 1000 2
    1080 810 1
    1433 1080 1
    1440 1080 9
    1860 880 2
    1920 909 2

    1920 1080 119

    240 240 4
    256 256 123
    512 512 3
    608 608 1
    810 810 32
    880 880 2
    1024 1024 21

    The rest:
    121 256 11
    144 256 7
    192 256 18
    256 121 1
    256 144 15
    256 192 6
    256 193 1
    768 1024 2

    So as you can see, there is quite a bit of variation. I *believe* that if I use the following:

    occ config:app:set previewgenerator squareSizes –value=”256 810 1024″
    occ config:app:set previewgenerator widthSizes –value=”256″
    occ config:app:set previewgenerator heightSizes –value=”256″
    occ config:system:set preview_max_x –value 1920
    occ config:system:set preview_max_y –value 1080

    That should generate the vast majority of the previews needed for my devices.

Leave a Reply

Your email address will not be published. Required fields are marked *