First you need to know how to connect to your Heroku application using bash. You can then use the du -h command to get a read on how big the files inside your slug are.
Once you’ve done that, here’s the magic command that will show you how big each folder in your slug is:
Max-depth of 1 will give you 1 level deep output of how big each of those root folders are. You can change the max-depth to see more granular introspection of each folder. (However, realistically, it is probably more useful to cd down to some subfolders and run du -h --max-depth=1 again.)
Some observations I have made:
1. Obviously you basically want to get as much out of your assets/ folder as you possibly can. Almost everything I do these days is tied to some kind of managed content, so I can safely put almost all the images and videos in my app into a Paperclip-backed data model. Using S3, Paperclip stores all the different sized versions it will render remotely, so all that stuff stays out of the slug.
2. Beware of Gem bloat. If you don’t use it, you probably want to get it out of there.
3. Generally speaking just keep large files out of your app. If you’re needing a lot of larger data files re-think your architecture to work in a more distributed, background job kind of way that doesn’t require the files to be in the slug. (Remember, worker dynos can always download from or upload to S3 and storage on S3 is much cheaper than keeping things in your slug.)
4. Use .slugignore (well documented so I won’t go into it here.)
5. I found that using gems directly from Rubygems seems to save a lot of space compared to using gems which point to a Github repo.
You can recognize a gem pulled from its Rubygems version because it usually has few or no parameters, or only a version parameter:
(pulling from Rubygems)
It turns out that because Spree can be a little lazy about building the Gems, they recommend you just point your Gemfile to the github repo. (To be fair, they maintain a lot of bugfixes across several branches, and pointing to a branch on Github makes much more sense if you have software that is retroactively fixed like Spree)
(Pointing to a github repo)
The difference here is that Bundler can just pull a compiled gemfile in the first example, whereas it has to download the repo and turn it into a Gem in the second example. In my app, the latter (pulling from Rubygems) saves me a whopping 70 MB compressed in my slug. Although I haven’t confirmed, I suspect this is because Bundler is actually very efficient at packaging up a Gem and excludes all the support files you don’t want when you create the gem, whereas the ‘lazy’ way of just pointing to a Git repo has the side-effect of including all the files in the repo in your finished slug.