This article was originally included in the October issue of the Engine Yard Newsletter. To read more posts like this one, subscribe to the Engine Yard Newsletter.
In Inside Rails, Yehuda Katz, Rails expert and core team member, and Carl Lerche, Rails expert and full-time contributor, present expert advice and insight on the Rails platform and Rails development.
Server-side programmers tend to spend a lot of time tuning their server-side code. Studies show, however, that 90 percent of the user’s perceived performance is on the client-side. The YSlow recommendations are the gold standard for client-side performance, providing a list of things web developers can do both on the server-side and the client-side to improve performance. If you use Rails, a large number of these recommendations are baked into the framework.
These tips are not extremely difficult to implement yourself with another framework, but Rails and Engine Yard believe in making your websites fast by default: you shouldn’t need to understand all the minutiae in order to get a snappy application.
Use Far-Future Expires
YSlow recommends using an Expires header set far into the future. This means that browsers don’t need to ask for your images, JavaScripts, or stylesheets again after the first request. However, this introduces an additional problem: what happens if you (inevitably) change these files? Won’t the browser be stuck with the old file forever?
The solution is to include a last modified timestamp with your assets (something like <img src="/images/myasset.png?84392578943" alt="" />). When the file is modified, you update the timestamp, and the browser will know to ask for the file again.
When you use Rails, this timestamping is the default behavior; all you need to do is set up your Nginx or Apache config to serve with far future headers and you’re ready to go. And if you use Engine Yard, we set up those headers for you.
GZip Components
YSlow recommends GZipping JavaScript, CSS, and other textual assets. This reduces their file size over the wire by approximately 70%. This can be set up using your Apache or Nginx config. If you use Engine Yard, your assets are gzipped by default.
Split Components Across Domains
Some older browsers (*cough* IE *cough*) will only download two assets from a host at a time. This means that if you have two JavaScript files, two CSS files, and 10 images, these assets will come down two at a time, even though the user’s connection is fast enough to download them in parallel. The solution to this problem is to split your assets up over multiple hosts (assets0.yourapp.com, assets1.yourapp.com, and so on).
When using server-side code you wrote yourself, or using a traditional server-side framework, you’d be forced to go through all of the URLs you generated and update them to use an asset host helper. With Rails, you can simply add a single line to your configuration and all of your generated URLs will start using the asset hosts you specified:
config.action_controller.asset_host = "assets%d.yourapp.com"
Of course, you’ll need to set up a CNAME entry in your DNS to point the new virtual domains at the same host, but that should be trivial.
This also single-handedly resolves another YSlow recommendation: “Use Cookie-free Domains for Components.” If your assets and application are on the same domain, the browser and server will pass cookies back and forth (up to 4k worth) for each asset request. By using asset hosts for your assets, you get the side benefit of cookie-free domains for your assets.
When comparing frameworks, it’s tempting to look at something like “Etag Support” as a feature and simply check it off. Looking under the surface, however, there are complex considerations that are begging to be abstracted away from you. Why should you have to know what the header name in the request is called (If-None-Match) or how to generate a reliable unique key for an object?
Rails makes working with these ideas drop-dead simple, so you won’t have to stress about following web best practices; when using Rails, you’ll be doing the right thing and hardly know it. Stay tuned for a follow up post on more of the ways Rails makes fast page loading a breeze.

Watch a Live Demo of Engine Yard AppCloud
The Engine Yard Newsletter
concatenating files like *.js and *.css help as well, its easier to request one file than 50.
Yep! Yet another thing Rails does for you. I plan to have more details on additional Rails help next week :)
You probably don't want the server to bother compressing images (jpg, gif, png) do you?
Why not?
Because they should already be compressed. I can't say I've done any real-world testing on this myself but I would have thought that compressing files that have already been compressed would be unlikely to reduce the file size by any great deal while forcing the client to work harder to render them. I'll happily proved wrong however.
Yeah my bad. I'll correct the post.
You'll need assets0.yourapp.com..assets3.yourapp.com when using config.action_controller.asset_host = "assets%d.yourapp.com", not starting from 1 as this blog implies. Action view helper does source.hasn % 4 to calculate the number %d is substituted by.
You should not be gzipping images. Images should already be compressed so all you are doing is consuming server cycles and browser cycles to gzip and ungzip.
From Yahoo: "Image and PDF files should not be gzipped because they are already compressed."
Good catch. You should be gzipping CSS, JS and HTML, not images.
Good catch. You should be gzipping CSS
ie6 has a bad support of gzipped documents, so it must be used carefully
What year is this again? Unless there is a business requirement (e.g., legacy install that can't be upgraded), IE6 should be ignored. You should do your best to talk a client or manager out of it. Give it up. IE6 is dead. Now let it rest in peace. I don't remember IE5 taking this long to disappear.
http://ie6update.com/
IE5 didn't take this long to disappear because IE6 didn't require a license check constantly like IE7. Hence why so many people don't want to upgrade – because they know they're on pirated gear and don't want to pay. But yes, if you can negotiate the requirement out do so – or at least charge extra for it.
Absolutely agree. IE6 must die. Gues'… it's already dead but not everywhere. Come on dude, you droped a link with updates, but I'll tell u' what people around the world using ie6 99% of them even don't know about that link but the most problem is not only knowing about such things, people are scared to make updates. That is the problem when everything suites them. They just do not won't. As a good developer that want's to earn some money it's not a good strategy to piss those people off. U need to take care of them firstly. Some day ie6 will die completely but before, it's just our mission to make web-aps that support ie6. That's my vision of things, am I right or not, I'm still wining the bigger amount of users around the world =)
What a funny title: "Your Pages Will Load Faster with Rails!"
That's like titling a blog post "The Air in San Francisco will keep you Alive!"
It implies that it is the converse of something else. Namely, that rails is faster than other frameworks. When that's just not the case. Maaaannny frameworks have these bells and whistles. Your pages won't load faster with rails. Rails is CONFIGURED to load your pages faster. Very suggestive title.
It's good to see these features as part of it, but definitely misleading.
I'd love to see some examples of other frameworks that provide asset hosts via a single configuration option, timestamped query string, and automatic concatenation of collections of JavaScript and CSS files. Again, I want to see this provided as part of the normal helpers, and not require changing a bunch of locations to opt into asset hosts, for instance.
If you want to add asset timestamps to images referenced from your stylesheets (which, in my apps at least, the majority are) the Compass CSS framework has a image_url method which will do the magic for you.
> Some older browsers (*cough* IE *cough*)
To be fair, IE 8 doesn't have this limitation and older versions of Firefox (2.5 and earlier) had the same exact problem.
I mentioned this briefly on the Temple mailing list but one thing I'd like to see in Ruby templating languages and web frameworks is the ability to render the template directly to the socket rather than buffering it in memory and sending once the whole page is completed.
Of course the OS is going to buffer some of the response for you but if you could flush at a specific time (like say just before <body>) then the browser can start downloading the CSS and images while the server works away on the body.
I know you're working hard on removing latency and speeding up Rails in general but I haven't heard anything about this specifically.
@dan we have actually been looking into this… one difficulty involves the way Ruby layouts typically work — they essentially require rendering the template first, and then inserting it into the template. If the user guaranteed that no state would be set in subviews and then expected to be available in the layout, we could do additional tricks. Expect to hear more about this after 3.0.
I don't know where I read this: some versions of squid, had a default configuration where yada.js?20091215 are handled the same way as yada.js, there is, no point in using the serial in the URL. While some others versions of Squid came with the right config.
As far as I know, the best way to handle this in a 100% way, is to version the filename itself, such as "yada.20091215.js", and having mod_rewrite (htaccess) rewrite it to the actual filename, which is yada.js. This preserves the actual filenames in Git, for example, and all proxy servers will see it's a different file.
The same solution in PHP here:
http://particletree.com/notebook/automatically-ve...
Cheers!
I've seen a lot of performance improvements with gzipping content on a forum which has a lot of pageviews/visit.
I don't know why, but I repeatedly think that using the 'I'll do it all' languages like Rails is like treatment by Chiropractors, simply not knowing whats happening under the surface.
two things real quick
1. Rails is a Framework, not a Language.
2. Read some source code for once, that's why its open.
Thanks for the great article. Can you share what Apache config directives EngineYard uses for the far-future expiry?
Engine Yard is an nginx-only shop, AFAIK http://www.engineyard.com/technology/stack
Using timestamped query strings for managing asset caching isn't reliable – some caching proxies ignore query strings. For improved cacheability you're better off using fingerprinted file names. There's a Rails AssetFingerprint plugin to help with this that I'm shamelessly promoting. More info here:http://blog.eliotsykes.com/2010/05/06/why-rails-a...
HTH – Eliot
Using timestamped query strings for managing asset caching isn't reliable – some caching proxies ignore query strings. For improved cacheability you're better off using fingerprinted file names. There's a Rails AssetFingerprint plugin to help with this that I'm shamelessly promoting. More info here:http://blog.eliotsykes.com/2010/05/06/why-rails-a...
HTH – Eliot