Heroku File Storage: What Actually Works in 2026
Heroku File Storage: What Actually Works in 2026
If you are trying to store uploaded files on Heroku, the short answer is simple: do not rely on your app's local disk for permanent file storage.
Heroku dynos use an ephemeral filesystem. That means files written to disk can disappear when a dyno restarts or gets replaced. This is why file uploads often seem to work during testing, then quietly break later when users try to access a file that no longer exists.
That does not mean Heroku is a bad place to run apps with uploads. It means you need the right storage pattern. In practice, most teams end up choosing one of four paths: cloud object storage such as S3, Rails Active Storage with a cloud backend, direct browser-to-storage uploads, or a hosted upload service that handles the plumbing for you.
This guide explains how Heroku file storage really works, why uploads disappear, and how to choose the simplest reliable setup for your app. If you want a broader framing on upload UX, the companion guides on easy upload and easy file upload go wider. This article stays focused on the Heroku-specific storage problem.
Does Heroku have persistent file storage?
Not in the way most teams mean it.
You can write files to disk inside a Heroku dyno, but that disk is not durable storage for user uploads. It is best treated as temporary working space. If your app writes uploaded images, PDFs, or attachments to the local filesystem and expects them to remain there indefinitely, that setup is fragile by design.
This is the core misunderstanding behind many Heroku upload issues. Local disk on Heroku is useful for temporary processing. It is not the right place to keep files that users need to retrieve later.
Why uploaded files disappear on Heroku
The problem is not usually your upload form. The problem is where the file lands after upload.
Heroku runs apps on dynos that can restart, cycle, or be replaced. When that happens, files written to the dyno filesystem do not behave like files sitting on a long-lived server you manage yourself. If those files are not part of the deployed slug, they are not something you should count on keeping.
This is why uploads can look fine at first. A user uploads a file. The app stores it locally. The app can still read it for a while. Then the dyno restarts, the file is gone, and the broken link shows up later in a support ticket.
Rails teams run into this with Active Storage when it is left on local mode. Non-Rails teams run into the same thing with custom upload endpoints that write into `tmp`, `public/uploads`, or another local directory. Different stack, same underlying mistake.
Your main options for Heroku file storage
There is no single correct answer for every app. The best option depends on how much control you want, how much infrastructure work you are willing to own, and whether file uploads are core product functionality or just important plumbing.
1. Use S3 or another object store
Best for: teams that want a durable, standard storage layer and are comfortable wiring it up.
This is the default recommendation for most Heroku upload architectures. Store uploaded files in Amazon S3 or another object storage service rather than on the dyno itself. Your app keeps metadata and file references, while the actual file lives in durable storage built for that purpose.
The upside is reliability and flexibility. The downside is the implementation work around credentials, access control, bucket policies, file naming, lifecycle rules, and delivery behavior. S3 is a strong foundation, but it is still infrastructure you own.
If your team is comfortable with cloud storage patterns, this is often the cleanest long-term choice.
2. Use Rails Active Storage with a cloud backend
Best for: Rails apps that want a Rails-native abstraction without storing files locally.
Active Storage works fine on Heroku as long as you do not leave it on local storage for production uploads. The important part is backing it with cloud storage such as S3. That gives you the Rails integration benefits while avoiding the ephemeral filesystem trap.
This is often the most natural option for Rails teams because it preserves the conventions they already understand. The tradeoff is that you still need to configure and manage the storage backend correctly.
If you are already in Rails and do not mind the S3 setup, this is a practical path.
3. Upload directly from the browser to storage
Best for: apps that want to reduce backend load and avoid proxying file data through the dyno.
A direct-upload flow usually works like this:
- Your app generates a signed upload target or client-side config.
- The browser uploads the file straight to cloud storage.
- Your app stores the resulting file URL or object key.
This approach is attractive on Heroku because it avoids routing large uploads through the app server. That can improve performance and reduce operational strain. It also pushes more complexity into signing, permissions, CORS, and edge-case handling.
Direct-to-storage uploads are powerful. They are not automatically simple.
4. Use a hosted upload service or add-on
Best for: small SaaS teams, solo founders, and product teams that want working uploads without building a storage subsystem.
This is often the most practical answer when uploads matter, but upload infrastructure is not the product. A hosted service handles the browser-side uploader, cloud storage path, and file delivery layer so your app can focus on receiving the result instead of reinventing the whole pipeline.
On Heroku specifically, this route has a strong logic to it. Heroku's own add-on ecosystem includes options designed around the fact that dyno filesystems are ephemeral. The goal is straightforward: get files from the user's browser into durable cloud storage without making your dyno responsible for hanging onto them.
This is where Simple File Upload fits naturally. It is also available as a Heroku add-on, and the product is built around direct browser-to-cloud uploads. That means you avoid the local-disk problem entirely. For teams that do not want to spend roadmap time on storage plumbing, that is a very rational trade.
How to choose the right Heroku file storage setup
Most teams do not need the theoretically most flexible solution. They need the one that fits their current constraints.
If you are building a prototype or internal tool
You can sometimes get away with a simpler setup early on, but be careful about normalizing a local-disk pattern you will later have to unwind. Even small tools have a way of becoming more important than expected.
If the upload is truly temporary, local disk may be acceptable. If users will need the file later, move to durable storage immediately.
If you are running a Rails app with user uploads
Use Active Storage with a cloud backend. This is usually the cleanest Rails-native path. Keep the abstraction you want, but make sure the actual files live outside the dyno.
If you are a small SaaS team without much infra appetite
Favor lower ownership. This is the most common case. Uploads are important, but they are not the reason users pay you. A hosted upload service or well-scoped add-on is usually a better use of engineering time than rolling your own end-to-end upload stack.
This is especially true if what you really need is an upload widget, stable file URLs, and a clean event or API response after upload. Owning less often means shipping faster and breaking less.
If uploads are core product infrastructure
Own more of the stack. If your product is deeply tied to media processing, compliance-heavy storage rules, or complex file workflows, a direct-to-S3 or more custom architecture can be worth the extra work.
Just be honest about the cost. Teams often say they want full control when what they really want is fewer surprises. Those are not the same thing.
Common Heroku file storage mistakes
Storing uploads on local disk
This is the classic mistake. It works until it does not. If a user-uploaded file needs to persist, local disk inside the dyno is the wrong destination.
Assuming the slug is storage
Your deployed slug is application code and bundled assets, not a place for runtime user uploads. Treating it as one leads to confusion fast.
Proxying every upload through your app by default
Sometimes this is necessary. Often it is just inherited architecture. For larger files or higher volume, routing everything through the dyno can become a bottleneck you did not need to create.
Ignoring delivery, permissions, and cleanup
Upload is only the first half of the problem. You also need to think about who can access the file later, how URLs are exposed, how expired or deleted files are handled, and whether private uploads should ever be public by default.
A practical path for most small teams
For many teams, the real requirement is not "build a beautiful cloud storage architecture." It is "let users upload files in our app, keep those files available, and do not turn this into a two-week detour."
That is why a low-ownership approach is often the right one on Heroku. If you already have strong S3 patterns in-house, use them. If you are in Rails and happy with Active Storage, use that with S3. If neither of those is true, it is worth asking a blunt question: is this really work your team should own?
Simple File Upload is a good example of the alternative. Instead of wiring together the front-end uploader, browser-to-cloud path, and file delivery concerns yourself, you can use a hosted service that was explicitly designed to avoid Heroku's filesystem limitations. That is not the only valid answer, but for small teams it is often the most economical answer in practice.
If you are comparing neighboring implementation paths, the follow-up guides on best JavaScript file upload, affordable file uploader for startups, and easy upload go deeper into those tradeoffs.
FAQ
Does Heroku store uploaded files permanently?
Not if you store them on the dyno filesystem. Permanent uploads should live in durable object storage or a hosted upload service, not on local disk inside the app runtime.
Can I use Active Storage on Heroku?
Yes. The important part is using a cloud storage backend rather than local storage for production uploads.
Should I upload directly to S3 on Heroku?
Direct-to-S3 is a good option if you want control and are comfortable managing signed uploads, CORS, and storage behavior. It is a strong architecture, but not always the simplest one for a small team.
What is the easiest Heroku file storage option?
Usually the option that gets files from the browser into durable cloud storage with the least custom infrastructure. For many small apps, that means a hosted upload service or add-on. For teams with stronger cloud experience, S3-backed uploads may still be the best fit.
Final take
Heroku file storage is only confusing if you expect the dyno filesystem to behave like a traditional persistent server disk. Once you stop making that assumption, the decision gets simpler.
If you want control, use object storage and wire the flow carefully. If you want a Rails-native path, use Active Storage with a cloud backend. If you want the fastest reliable path for a small team, use a hosted upload approach that avoids the dyno filesystem entirely.
The right answer is not the one with the most architectural purity. It is the one that keeps user files available and keeps your team focused on features that actually matter to the product.